【问题标题】:Accessing 2 UI items from a 3rd thread in WPF从 WPF 中的第三个线程访问 2 个 UI 项
【发布时间】:2010-01-07 00:22:47
【问题描述】:

我有一个由工作线程(不是 UI 线程)创建的 BitmapFrame 对象并放置在静态集合中。

然后,我有一个不同的工作线程将此对象分配给 UI 线程拥有的 Image 对象。

如你所想,我无法访问Image 对象(因为它属于 UI 线程),我得到:"calling thread cannot access the object because different thread owns it"

所以,我尝试通过执行以下操作来解决它:

imageMainImage.Dispatcher.BeginInvoke(System.Windows.Threading.DispatcherPriority.Normal, new Action<ImageItem>(delegate(ImageItem A) {
    imageMainImage.Source = A.ManipulatedPreview;                
}), II);

IIImage 项(由工作线程创建并通过静态类可用),imageMainImage 是 UI 线程拥有的 Image 对象。

但现在,我又得到了"calling thread...",但这次我得到了它,因为II 对象属于不同的线程(第一个工作线程)。

我想要做的是让一个线程处理属于不同线程的 2 个 Image 元素。

我正在尝试以不同的方式处理整个过程,但我想知道,有没有解决方案?

谢谢。

【问题讨论】:

  • +1:有趣的问题。我的猜测:您会得到的最佳答案是“不,没有解决方案”。希望我错了:-)
  • 我有一种很好的感觉,没有办法做到这一点。如果有办法将对象“所有权”从一个线程传递到另一个线程,我会很满意。

标签: c# wpf multithreading


【解决方案1】:

您需要首先在 Dispatcher 上调用 CheckAccess() 以查看您是否在 UI 线程上,因此是否能够更新 UI 项。

这是我为更新 WPF 中的组合框而编写的一个辅助函数,您可以轻松地调整它以适应 Image 控件,它是 CheckAccess 调用的一个很好的例子:

    private void UpdateComboDataSource<T>(ComboBox ctrl, IEnumerable<T> datasource, string displayPath, string valuePath)
    {
        if (ctrl == null)
            throw new ArgumentNullException("Control to be bound must not be null");

        //check if we are on the control's UI thread:
        if (ctrl.Dispatcher.CheckAccess())
        {
            //we have full access to the control, no threading issues, so let's rip it up and databind it
            datasource = datasource.OrderBy(x => x);
            if (displayPath != null && ctrl.DisplayMemberPath == null)
                ctrl.DisplayMemberPath = displayPath;
            if (valuePath != null && ctrl.SelectedValuePath == null)
                ctrl.SelectedValuePath = valuePath;

            ctrl.ItemsSource = datasource;
        }
        else
        {
            //we don't have full access to the control because we are running on a different thread, so 
            //we need to marshal a call to this function from the control's UI thread
            UpdateComboDataSourceDelegate<T> del = new UpdateComboDataSourceDelegate<T>(this.UpdateComboDataSource);
            ctrl.Dispatcher.BeginInvoke(del, ctrl, datasource, displayPath, valuePath);
        }
    }


private delegate void UpdateComboDataSourceDelegate<T>(ComboBox ctrl, IEnumerable<T> dataSource, string displayPath, string valuePath);

所以该函数检查它是否有访问权,如果有,它会分配数据源。如果没有,那么它会回调自己,但这次是在 UI 线程的上下文中。

可能有一种更简洁的方式来对委托创建进行编码,但这对于试图理解示例的人来说并不是那么好,因此需要明确的委托定义。

【讨论】:

  • 我的第一反应是“niicceee .....”,但在阅读了一行又一个之后,我的反应变成了“Yaiks!!”,扭曲的恐怖代码有效。
  • 它看起来很糟糕,但是整个自调用函数的事情是得到认可的方式,我所做的只是加强过程以满足我的特定需求。你的可以简单得多,特别是如果你让委托创建/声明更简洁。
猜你喜欢
  • 1970-01-01
  • 2016-09-17
  • 1970-01-01
  • 1970-01-01
  • 2021-07-30
  • 1970-01-01
  • 2014-12-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多