我怎样才能给 Dispatcher.Invoke 一个论点?

Posted

技术标签:

【中文标题】我怎样才能给 Dispatcher.Invoke 一个论点?【英文标题】:How can I give an argument to Dispatcher.Invoke? 【发布时间】:2021-08-21 10:49:30 【问题描述】:

我正在尝试在后台线程中加载 BitmapImage,然后将 (WPF) 图像源设置为此 BitmapImage。

我目前正在尝试这样的事情:

public void LoadPicture()

    Uri filePath = new Uri(Directory.GetCurrentDirectory() + "/" + picture.PictureCacheLocation);
    if (Visible && !loaded)
    
        if (File.Exists(filePath.AbsolutePath) && picture.DownloadComplete)
        
            BitmapImage bitmapImage = LoadImage(filePath.AbsolutePath);
            image.Dispatcher.Invoke(new Action<BitmapImage>((btm) => image.Source = btm), bitmapImage);

            loaded = true;
        
    

但我得到一个InvalidOperationException,因为后台线程拥有 BitmapImage。 有没有办法将 BitmapImage 的所有权或副本提供给 UI 线程?

我需要在后台线程中加载位图图像,因为它可能会阻塞很长时间。

【问题讨论】:

使用async/await 而不是摆弄Invoke。这自 2012 年以来就没有必要了。此外,仅当后台线程调用 LoadPictureLoadImage 使用线程时,bitmapImage 才会由后台线程拥有。贴出缺少的代码 此外,您可以创建一个BitmapImage,直接使用var bitmapImage=new BitmapImage(filePath); 从文件中加载数据。使用Path.Combine而不是直接连接字符串 由于代码使用的是 current 文件夹,因此无需连接。 var filePath=new Uri(Path.GetAbsolutePath(picture.PictureCacheLocation)); 类似于this 的东西可能有用。冻结并从 Task 操作返回 BitmapImage 另外,picture.DownloadComplete 似乎表明您首先下载图像,然后将其写入文件,然后从该文件创建 BitmapImage。请注意,您可以直接从远程 URL 创建 BitmapImage。 【参考方案1】:

使用 DependencyObject 的所有工作都应在一个线程中进行。 除了 Freezable 的冻结实例。

将参数传递给 Invoke 也没有意义(在这种情况下) - 最好使用 lambda。

还有Dispatcher自锁的危险,因为你没有检查流。

    public void LoadPicture()
    
        Uri filePath = new Uri(Directory.GetCurrentDirectory() + "/" + picture.PictureCacheLocation);
        if (Visible && !loaded)
        
            if (File.Exists(filePath.AbsolutePath) && picture.DownloadComplete)
            
                BitmapImage bitmapImage = LoadImage(filePath.AbsolutePath);

                bitmapImage.Freeze();

                if (image.Dispatcher.CheckAccess())
                    image.Source = bitmapImage;
                else
                    image.Dispatcher.Invoke(new Action(() => image.Source = bitmapImage));

                loaded = true;
            
        
    

Frеezable 类型的对象并不总是允许自己被冻结。 但是您的代码不足以识别可能存在的问题。 如果冻结失败,再展示LoadImage(Uri)方法是如何实现的。

【讨论】:

image.Dispatcher.CheckAccess() 在您知道自己处于 UI 线程以外的线程中时毫无意义。 我同意。但是从显示的代码中,我无法得出类似的结论。 TС 写道,他在从后台线程调用方法时遇到了问题。但他并没有写到他总是只从后台线程调用这个方法。 我真的不再需要这个了,因为我发现了一个错误,为什么 LoadImage 会阻塞这么长时间,所以我可以在 Invoke 中加载它。但这仍然是一个非常有用的答案,谢谢。 您能否详细说明一下调度程序的访问是如何工作的以及它何时自锁?此方法有时会从 ui 线程调用,但绝不应该从另一个 Dispatcher.Invoke 调用

以上是关于我怎样才能给 Dispatcher.Invoke 一个论点?的主要内容,如果未能解决你的问题,请参考以下文章

等待 Dispatcher.InvokeAsync 与 Dispatcher.Invoke

使用 Dispatcher.Invoke 从非主线程更改 WPF 控件

C# Dispatcher Invoke 和正常代码执行顺序

Application.Current.Dispatcher.BeginInvoke(action) VS。 Application.Current.Dispatcher.Invoke(action)

dispatcher invoke 会导致主程序闪退吗

在 Dispatcher.Invoke() 中使用 lambda 表达式作为参数