2011-10-23 52 views
6

我有一個用wpf編寫的應用程序,它可以下載一些網頁,解析html代碼並保存一些值。必須在DependencyObject的同一線程上創建DependencySource

class ListOfItems 
{  
    public List<SomeObject> 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類是做所有的工作(有一些其他方法用於使代碼可讀)的方法 - 下載源,解析和填充數據,f.e. ListToBind

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

正如你可以看到,當這種方法DownloadItems完成了工作,OnDownloadCompleted事件引發的。在主線程下面的代碼在MainWindow.xaml

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

DataGrid中充滿了價值,因爲下面的XAML代碼段。

<DataGrid Name="dataGrid" AutoGenerateColumns="False"> 
    <DataGrid.Columns> 
     <DataGridTextColumn Header="Tag" Binding="{Binding Name}"/> 
     <DataGridTextColumn Header="Color" Binding="{Binding MyClass.Percentage}"> 
      <!--<DataGridTextColumn.CellStyle> 
       <Style TargetType="DataGridCell"> 
        <Setter Property="Background" Value="{Binding MyClass.Color}" /> 
       </Style> 
      </DataGridTextColumn.CellStyle>--> 
     </DataGridTextColumn> 
    </DataGrid.Columns> 
</DataGrid> 

它工作得很好。但是有這個問題。嘗試取消註釋評論的xaml片段,你會得到Must create DependencySource on same Thread as the DependencyObject.錯誤。

最後,我的問題是,如何避免這個錯誤?

編輯:

它應該是這樣到底。這張照片取自MS Excel,並在Adobe Photoshop中着色。

example

回答

22

SolidColorBrush是一個Freezable它是派生的DispatcherObject。 DispatcherObjects具有線程關聯 - 即只能在創建它的線程上使用/交互。然而,Freezables提供了凍結實例的功能。這將阻止對該對象的任何進一步更改,但它也會釋放線程關聯。因此,您可以更改它,以便您的屬性不存儲像SolidColorBrush這樣的DependencyObject,而只是存儲Color。或者,您可以凍結使用Freeze方法創建的SolidColorBrush。

+0

謝謝你的解釋。這個問題的第二個答案可能是相同的方式,但問題是我不知道,什麼要凍結。現在,當你告訴我SolidColorBrush是從DispatcherObject派生出來的,並解釋了這種情況後,我就開始工作了。再次感謝你,賞金是你的。 –

1

我認爲標準方法是將它傳遞給另一個線程之前獲得來自FreezableFreeze它的數據對象。一旦對象被凍結,你就不能再改變它了,所以沒有線程錯誤的危險。

另一個選項可能是讓數據對象成爲一個普通的C#對象(不是派生自DispatcherObject)並且自己實現INotifyPropertyChanged

+0

PropertyChanged事件不一定必須發生在UI線程上,因爲它們[自動封送到UI線程。 [http://stackoverflow.com/a/11015784] – user1912383

+0

@ user1912383:當然,你是對的。但5年前我不知道... – Niki

相關問題