Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/293.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 使用NotifyPropertyChange异步设置Image.Source_C#_Wpf_Asynchronous_Inotifypropertychanged - Fatal编程技术网

C# 使用NotifyPropertyChange异步设置Image.Source

C# 使用NotifyPropertyChange异步设置Image.Source,c#,wpf,asynchronous,inotifypropertychanged,C#,Wpf,Asynchronous,Inotifypropertychanged,我有一个通过一些滑块修改的图像,其值被发送到一个方法,该方法按程序重新生成位图源 由于滑块的运动滞后,目前的事情很麻烦。我相信这是由于Update方法的阻塞性 我试图使事情更加异步,但显然没有成功,因为滑块运动仍然滞后 我在下面发布了我的代码,问题是:我做错了什么,在WPF中异步更新程序生成的图像的正确方法是什么 需要注意的一点是IDE抱怨没有等待更新调用,在调用完成之前执行仍在继续,但我不确定这意味着什么,或者我应该怎么做 MainWindow.xaml <Window x:Class=

我有一个通过一些滑块修改的图像,其值被发送到一个方法,该方法按程序重新生成位图源

由于滑块的运动滞后,目前的事情很麻烦。我相信这是由于Update方法的阻塞性

我试图使事情更加异步,但显然没有成功,因为滑块运动仍然滞后

我在下面发布了我的代码,问题是:我做错了什么,在WPF中异步更新程序生成的图像的正确方法是什么

需要注意的一点是IDE抱怨没有等待更新调用,在调用完成之前执行仍在继续,但我不确定这意味着什么,或者我应该怎么做

MainWindow.xaml

<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);
    }