C# 使用NotifyPropertyChange异步设置Image.Source
我有一个通过一些滑块修改的图像,其值被发送到一个方法,该方法按程序重新生成位图源 由于滑块的运动滞后,目前的事情很麻烦。我相信这是由于Update方法的阻塞性 我试图使事情更加异步,但显然没有成功,因为滑块运动仍然滞后 我在下面发布了我的代码,问题是:我做错了什么,在WPF中异步更新程序生成的图像的正确方法是什么 需要注意的一点是IDE抱怨没有等待更新调用,在调用完成之前执行仍在继续,但我不确定这意味着什么,或者我应该怎么做 MainWindow.xamlC# 使用NotifyPropertyChange异步设置Image.Source,c#,wpf,asynchronous,inotifypropertychanged,C#,Wpf,Asynchronous,Inotifypropertychanged,我有一个通过一些滑块修改的图像,其值被发送到一个方法,该方法按程序重新生成位图源 由于滑块的运动滞后,目前的事情很麻烦。我相信这是由于Update方法的阻塞性 我试图使事情更加异步,但显然没有成功,因为滑块运动仍然滞后 我在下面发布了我的代码,问题是:我做错了什么,在WPF中异步更新程序生成的图像的正确方法是什么 需要注意的一点是IDE抱怨没有等待更新调用,在调用完成之前执行仍在继续,但我不确定这意味着什么,或者我应该怎么做 MainWindow.xaml <Window x:Class=
<Window x:Class="Miotec.FranjasSenoidais.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:Miotec.FranjasSenoidais"
xmlns:toolkit="http://schemas.xceed.com/wpf/xaml/toolkit"
mc:Ignorable="d"
Title="MainWindow">
<Grid Margin="10">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Grid x:Name="Imagem" Grid.Row="0" Grid.Column="0">
<Image x:Name="franjas" Width="800" Height="600"
Source="{Binding ImageSource}"/>
</Grid>
<Grid x:Name="SliderLateral" Grid.Row="0" Grid.Column="1">
<toolkit:RangeSlider Orientation="Vertical"
Maximum="1" Minimum="0" Step="0.01"
HigherValue="{Binding Maximo}"
LowerValue="{Binding Minimo}"/>
</Grid>
<Grid x:Name="SliderEspessuraFranja" Grid.Row="1" Grid.Column="0">
<Slider Orientation="Horizontal" Value="{Binding Espessura}"
Minimum="4" Maximum="16"/>
</Grid>
</Grid>
</Window>
弗朗索瓦
public static class FranjasSenoidais
{
public static BitmapSource Criar(int largura,
int altura,
double maximo,
double minimo,
int espessura)
{
if (largura < 2 || altura < 2)
return null;
var targetBitmap = new RenderTargetBitmap(largura, altura,
96, 96,
PixelFormats.Pbgra32);
var visual = new DrawingVisual();
using (var dc = visual.RenderOpen())
{
double xcenter = largura * 0.5;
double ycenter = altura * 0.5;
dc.DrawEllipse(Brushes.Black, null, new Point(xcenter, ycenter), espessura, espessura);
}
targetBitmap.Render(visual);
targetBitmap.Freeze();
return targetBitmap;
}
}
我想你只需要一些改变@酷蓝评论是对的。只需将调度移到INotify实现中,并在任务上对cpu绑定的进程进行排队。确保从该线程触发已更改的属性,请参见以下内容:
private void Update() {
Task.Run(new Action(() => {
// somewhat lengthy operation
_imageSource = FranjasSenoidais.Criar((int)franjas.Width,
(int)franjas.Height,
Maximo, Minimo,
Espessura);
RaisePropertyChanged("ImageSource");
}));
}
public event PropertyChangedEventHandler PropertyChanged;
void RaisePropertyChanged(string name) {
Application.Current.Dispatcher.Invoke(() => {
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}, System.Windows.Threading.DispatcherPriority.Background);
}
对我来说,主窗口:窗口,INotifyPropertyChanged已经错误了。窗口不应更改INotifyPropertyChanged,而应仅更改viewmodelshould@Steve我知道,这就是为什么我要写简短的观察。此外,这个问题与MVVM无关,如果您没有绑定到MVVM,任何东西都可以实现INPC,IMO。使用Dispatcher.BeginInvoke没有帮助,因为当前的Dispatcher是UI线程调度器。尝试用Task.Run替换Dispatcher.BeginInvoke。这将计划线程池上的映像加载。另外,我认为您可以使用void作为更新方法的返回类型,因为您不需要在setters中等待它。@CoolBlue当我按照您的建议执行时,我得到一个InvalidOperationException,因为由于Task的原因,其他线程无法访问该对象。我想运行。我想如果您按照我的建议添加MainWindow.Dispatcher.Invoke=>RaisePropertyChangedImageSource,那么就可以了。仍然得到InvalidOperation,因为franjas在另一个线程中,并且它的属性是在任务内部访问。运行调用。实际上,正在设置的是_imageSource。
private void Update() {
Task.Run(new Action(() => {
// somewhat lengthy operation
_imageSource = FranjasSenoidais.Criar((int)franjas.Width,
(int)franjas.Height,
Maximo, Minimo,
Espessura);
RaisePropertyChanged("ImageSource");
}));
}
public event PropertyChangedEventHandler PropertyChanged;
void RaisePropertyChanged(string name) {
Application.Current.Dispatcher.Invoke(() => {
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}, System.Windows.Threading.DispatcherPriority.Background);
}