必须在与DependencyObject相同的Thread上创建DependencySource

我有一个用wpf编写的应用程序,它可以下载一些网页,解析HTML代码并保存一些值。

class ListOfItems { public List ListToBind; public void DownloadItems() { Task.Factory.StartNew(() => { ... ... if (OnDownloadCompleted != null) OnDownloadCompleted(this, EventArgs.Empty); } } } class SomeObject { public string NameOfItem; public MyClass Properties; } class MyClass { public int Percentage; public SolidColorBrush Color; } 

这是我正在使用的对象模型。 它是简化版本,我不希望你重新组织它,我有这样写道的原因。 在ListOfItems类中是执行所有工作的方法(内部使用一些其他方法使代码可读) – 下载源代码,使用数据解析和填充ListToBind ,fe

 [0] => NameOfItem = "FirstOne", Properties = {99, #FF00FF00} [1] => NameOfItem = "SecondOne", Properties = {50, #FFFF0000} etc. 

如您所见,当此方法DownloadItems完成其工作时,将引发OnDownloadCompleted事件。 在主线程中是以下代码

 void listOfItems_OnDownloadCompleted(object sender, EventArgs args) { dataGrid.Dispatcher.Invoke(new Action(() => { dataGrid.ItemsSource = ListOfItemsInstance.ListToBind; })); } 

由于遵循xaml代码片段, MainWindow.xaml上的DataGrid会填充值。

     <!--    -->    

它工作得很好。 但是有这个问题。 尝试取消注释已注释的xaml片段,您将获得Must create DependencySource on same Thread as the DependencyObject. 错误。

最后,我的问题是,如何避免这个错误?

编辑:

它最终应该看起来像这样。 此图片来自MS Excel并在Adobe Photoshop中着色。

例

SolidColorBrush是一个Freezable ,它是派生的DispatcherObject。 DispatcherObjects具有线程关联性 – 即它只能在创建它的线程上使用/交互。 然而,Freezables提供了冻结实例的能力。 这将阻止对对象的任何进一步更改,但它也将释放线程关联。 因此,您可以更改它,以便您的属性不存储像SolidColorBrush这样的DependencyObject,而只是存储Color。 或者,您可以使用冻结方法冻结您正在创建的SolidColorBrush。

我认为标准方法是从Freezable派生数据对象并在将其传递给另一个线程之前将其Freeze 。 一旦对象被冻结,您就不能再进行更改,因此不存在线程错误的危险。

另一种选择可能是使数据对象成为普通的C#对象(不是从DispatcherObject派生)并自己实现INotifyPropertyChanged

dataGrid.ItemsSource不足以在主线程上设置dataGrid.ItemsSource 。 您必须在主线程上创建每个项目。 就像是:

 List l = new List(); foreach(var item in ListOfItemsInstance.ListToBind) { l.Add(new SomeObject(){NameOfItem = item.NameOfItem, Properties = item.Properties }); } dataGrid.ItemsSource = l;