在线程中使用Dispatcher.BeginInvoke时出现奇怪的线程异常

时间:2014-04-27 06:24:07

标签: c# multithreading dispatcher

我在一个线程中运行一个非常耗时的方法,其中一件事就是,如果没有可用的图像,它会将名为Background的背景网格设置为纯色。以下是该代码段的外观:

SolidColorBrush scb = new SolidColorBrush();
scb.Color = Color.FromRgb(21, 21, 21);
Dispatcher.BeginInvoke(new Action(() => Background.Background = scb)); 

但我总是在这个地方遇到错误"Cannot use a DependencyObject that belongs to a different thread than its parent Freezable"

有谁知道为什么会这样? Dispatcher应该让这个问题消失,对吗?

以下是我如何调用方法(如果需要)

Thread BGthread = new Thread(HandleBackgrounds);
BGthread.Start();

2 个答案:

答案 0 :(得分:4)

SolidColorBrush是一个依赖项对象 - 您在非UI线程中创建它,然后尝试在UI线程中使用它。试试这个:

Action action = () =>
{
    SolidColorBrush scb = new SolidColorBrush(Color.FromRgb(21, 21, 21));
    Background.Background = scb;
};
Dispatcher.BeginInvoke(action);

当然只是在一个声明中:

Dispatcher.BeginInvoke((Action (() =>
    Background.Background = new SolidColorBrush(Color.FromRgb(21, 21, 21)))));

无论哪种方式,您都会在您传递给调度员的操作中创建SolidColorBrush

答案 1 :(得分:1)

BrushDispatcherObject,因此它具有线程关联性 - 它属于创建它的线程,通常只能由它使用。

但是,WPF有一个调度程序对象的子类,称为Freezable,您可以通过将它们设置为只读来删除线程关联。画笔是可以冻结的,因此您可以在一个线程上创建一个并将其传递给另一个:

var scb = new SolidColorBrush(Color.FromRgb(21, 21, 21));
scb.Freeze();
Dispatcher.BeginInvoke(new Action(() => Background.Background = scb)); 

如果您在视图模型中创建未在UI线程上创建的画笔,则此选项非常有用。另一个常见的用例是在不同的线程上解码图像,这可以提高性能(ImageSource也是可冻结的。)

冻结freezables也被视为performance optimization,因此请尽可能使用它。