2011-10-23 6 views
6

Ho un'applicazione scritta in wpf, che scarica alcune pagine Web, analizza il codice html e salva alcuni valori.È necessario creare DependencySource sullo stesso thread di DependencyObject

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

Questo è il modello oggetto che sto utilizzando. È una versione semplificata e non voglio che la riorganizzi, c'è una ragione per cui l'ho scritta in questo modo. In ListOfItems la classe è un metodo che fa tutto il lavoro (ci sono alcuni altri metodi usati all'interno per rendere leggibile il codice) - scarica sorgente, analizza e riempie ListToBind con dati, ad es.

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

Come si può vedere, quando questo metodo DownloadItems completa il suo lavoro, OnDownloadCompleted evento viene generato. Nel thread principale è seguente codice

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

DataGrid nella MainWindow.xaml è pieno di valori, a causa della seguente frammento di codice 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> 

Funziona bene. Ma c'è questo problema. Prova a commentare il frammento xaml snippet e otterrai l'errore Must create DependencySource on same Thread as the DependencyObject..

Infine, la mia domanda è, come evitare questo errore?

EDIT:

Esso dovrebbe essere simile alla fine. Questa immagine è presa da MS Excel e colorata in Adobe Photoshop.

example

risposta

22

Il SolidColorBrush è un Freezable che è un DispatcherObject derivato. DispatcherObjects ha affinità di thread - cioè può essere utilizzato/interagito solo con il thread su cui è stato creato. I freezone tuttavia offrono la possibilità di congelare un'istanza. Ciò impedirà ulteriori modifiche all'oggetto ma rilascerà anche l'affinità del thread. Quindi puoi cambiarlo in modo che la tua proprietà non stia memorizzando un oggetto DependencyObject come SolidColorBrush e invece memorizzi semplicemente il Colore. Oppure puoi bloccare il SolidColorBrush che stai creando usando il metodo Freeze.

+0

Grazie per questa spiegazione. La seconda risposta a questa domanda è probabilmente allo stesso modo, ma il problema era che non sapevo, cosa congelare. Ora, quando mi hai detto che SolidColorBrush è derivato da DispatcherObject e ho spiegato la situazione, l'ho fatto funzionare. Grazie ancora, la taglia è tua. –

1

Credo che il modo standard è quello di ricavare l'oggetto dati da Freezable e Freeze prima di passare ad un altro filo. Una volta che l'oggetto è congelato, non puoi più cambiarlo, quindi non c'è pericolo che infili bug.

Un'altra opzione potrebbe essere quella di rendere l'oggetto dati un oggetto C# semplice (non derivato da DispatcherObject) e implementare INotifyPropertyChanged da soli.

+0

Gli eventi PropertyChanged non devono necessariamente avvenire sul thread ui, perché sono [automaticamente portati al thread dell'interfaccia utente. [http://stackoverflow.com/a/11015784] – user1912383

+0

@ user1912383: hai ragione, ovviamente. Ma non lo sapevo 5 anni fa ... – Niki