【问题标题】:Long running operation - updating UI with BitmapImage doesn't work长时间运行的操作 - 使用 BitmapImage 更新 UI 不起作用
【发布时间】:2012-03-05 20:04:28
【问题描述】:

我很沮丧试图解决这个问题。为什么创建线程并在完成后更新 UI 如此复杂?!我已经尝试过thisthisthis,但我仍然无法清楚地了解整个多线程问题。在 Java 中这很容易......

无论如何,这是我的代码的简化版本,作为第三个链接的结果:

private delegate void SimpleDelegate2(BitmapImage bi);
private delegate void SimpleDelegate(string st1, string st2);

private void Process(string st1)
{
    try
    {
        string st2 = "test st2";
        SimpleDelegate del = new SimpleDelegate(LongRunningProcess);
        del.BeginInvoke(st1, st2, null, null);
    }
    catch
    {
        //do some failsafe thing
    }
}

private void LongRunningProcess(string st1, string st2)
{
    //do some long processing with the strings
    BitmapImage bi = new BitmapImage();//there will be an actual bitmap here

    SimpleDelegate2 del1 = delegate(BitmapImage bimg)
    {
        ImageControlOnWPFform.Source = bimg; //null;
    };
    this.Dispatcher.BeginInvoke(DispatcherPriority.Send, del1, bi);
}

这里的问题是我无法将 Image 控件的 Source 值设置为 bimg 但我可以将其设置为 null! 每当我尝试将其设置为bimg 我得到一个异常,说调用线程无法访问这个对象,因为另一个线程拥有它。我也尝试将其直接设置为bi,这也给出了相同的异常。

但是我可以毫无问题地将源设置为null,这意味着我可以修改Image控件的Source值。但是如何访问bibimg?我做错了吗?

另外:我注意到最后一个BeginInvoke 的给定参数与方法的任何重载都不匹配它们仍然被认为是有效的并且可以正常工作。当我指向BeginInvoke 时,我看到的方法重载集与我在方法名称后键入( 时出现的方法重载完全不同。为什么?

【问题讨论】:

  • 谢谢。我不知道这是一个与 BitmapImage 相关的问题,因此我没有找到那个问题。我认为我的多线程和委托的使用有问题。总之感谢。顺便说一句,你能批准我对你的答案的编辑吗? (不确定您是否可以这样做。) PS:我仍在为我的 Also 部分寻找答案。 :)
  • 最后一个 BeginInvoke 匹配到签名 BeginInvoke(DispatcherPriority 优先级,Delegate 方法,Object arg,params Object[] args)。 Params 参数被视为可选(无参数):msdn.microsoft.com/en-us/library/w5zay9db.aspx
  • @DarkGray 我找到了答案。我已经编辑了您的答案以包括解释。等待同行评审。

标签: wpf multithreading c#-4.0 visual-c#-express-2010


【解决方案1】:

回答主要问题

在 UI 线程中使用 BitmapImage 之前执行 bi.Freeze()Freeze 操作将使BitmapImage 只读且线程安全。

    ...
    //do some long processing with the strings
    BitmapImage bi = new BitmapImage();//there will be an actual bitmap here
    bi.Freeze();

    SimpleDelegate2 del1 = delegate(BitmapImage bimg)
    ...

回答

System.Windows.Threading.Dispatcher 类有五个BeginInvoke 方法的签名:

public DispatcherOperation BeginInvoke(Delegate method, params object[] args);
public DispatcherOperation BeginInvoke(DispatcherPriority priority, Delegate method);
public DispatcherOperation BeginInvoke(Delegate method, DispatcherPriority priority, params object[] args);
public DispatcherOperation BeginInvoke(DispatcherPriority priority, Delegate method, object arg);
public DispatcherOperation BeginInvoke(DispatcherPriority priority, Delegate method, object arg, params object[] args);

但是,其中三个签名(以DispatcherPriority priority 作为第一个参数的签名)上有以下标签:

[Browsable(false)]
[EditorBrowsable(EditorBrowsableState.Never)]

这就是为什么在方法名称后输入( 时它们不显示的原因。

【讨论】:

  • 我需要将 BitmapImage 设置为 Image 控件 (WPF),这是长时间运行操作的结果。我正在另一个线程中进行操作,但无法将生成的 BitmapImage 设置为 UI 线程中的 Image 控件。
  • 哪种长时间运行?
  • 操作细节是否必要?它只是做一些图像处理(15-30 秒),最后它给了我一个 BitmapImage。我必须在 UI 上显示这个生成的 BitmapImage(通过 WPF 表单上的 Image 控件)。还有另一种方法可以做到这一点吗?我正在尝试使用委托,这是从非 UI 线程更新 UI 的推荐方法,但不知何故它只是拒绝工作(空值除外)。
  • 奇怪的是有效!我不知道为什么会这样。请更新您的答案,如果可以,请解释它为什么有效。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-03-02
  • 2022-11-23
  • 1970-01-01
  • 2012-01-04
  • 2017-10-30
  • 2012-09-29
相关资源
最近更新 更多