2011-10-23 73 views
6

wpfで書かれたアプリケーションがあり、Webページをダウンロードして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では、クラスはすべてのジョブを実行するメソッドです(コードを読みやすくするために内部で使用されているいくつかのメソッドがあります) - ソースをダウンロードし、解析し、データを埋め込みます(ListToBind、f.e.

[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; 
      })); 
} 

データグリッドがあるため、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.というエラーが表示されます。

最後に、私の質問は、このエラーを回避する方法です。

EDIT:

それは最後に次のようになります。この写真はMS Excelから取り込まれ、Adobe Photoshopで色付けされています。

example

答えて

22

SolidColorBrushは、派生DispatcherObjectであるFreezableです。 DispatcherObjectsはスレッド親和性を持っています。つまり、作成されたスレッドでのみ使用/相互作用できます。しかしFreezablesはインスタンスをフリーズする機能を提供しています。これにより、オブジェクトのそれ以上の変更は防止されますが、スレッドの親和性も解放されます。そのため、プロパティを変更して、SolidColorBrushのようなDependencyObjectを格納せず、代わりにColorを保存することができます。または、Freezeメソッドを使用して作成しているSolidColorBrushをフリーズできます。

+0

この説明をありがとう。この質問の2番目の答えはおそらく同じ方法ですが、問題は私が知らなかったこと、何を凍結するかです。さて、SolidColorBrushがDispatcherObjectから派生し、状況を説明したと言ったとき、私はそれを動作させました。もう一度ありがとう、賞金はあなたです。 –

1

私は、標準的な方法は、別のスレッドに渡す前にFreezableFreezeそこからデータオブジェクトを導出することだと思います。オブジェクトがフリーズしたら、それ以上は変更することはできません。したがって、バグをスレッディングする危険はありません。

別のオプションは、データオブジェクトを平文のC#オブジェクト(DispatcherObjectから派生しない)にして、INotifyPropertyChangedを実装することです。

+0

PropertyChangedイベントはUIスレッドに自動的にマーシャリングされるため、UIスレッドで必ずしも発生する必要はありません。 [http://stackoverflow.com/a/11015784] – user1912383

+0

@ user1912383:もちろん、そうです。しかし、私は5年前のことを知らなかった... – Niki

関連する問題