2015-09-17 18 views
6

Ho un DatGrid, che è associato a var Result_Full = new ObservableCollection<IP_DataRow>(). Questa è una classe semplice contenente più stringa & double variabili. Niente di difficileAggiornamento ObservableCollection dallo sfondo Worker

Quello che faccio è che leggo un file Excel (con Telerik RadSpreadProcessing), che analizza le righe nella mia classe. Lo faccio su un thread in modo che l'interfaccia utente non sia bloccata. Ho incontrato alcuni problemi però:

1) Non posso usare ref parola chiave di un lungo processo che legge file excel (perché Result_Full è una proprietà pubblica legata a un DataGrid), ma devo creare temporanea ObservableCollection<IP_DataRow>(), dove la i valori sono posizionati Una volta che il processo è finito ho eseguito il seguente script per copiare i valori:

 foreach (var item in tmpFull) 
     { 
      InvokeOnUIThread(() => 
      { 
       Result_Full.Add(item); 
      }); 
     } 

Quello che vorrei fare, è quello di essere in grado di vedere in tempo reale (se possibile) come gli elementi vengono aggiunti la raccolta nel mio DataGrid.

Come sto utilizzando .Net 4.5 Ho cercato di attuare BindingOperations.EnableCollectionSynchronization come è stato suggerito da qualche altro post, ma non riuscivo a capire come associare il mio UI Bould collezione Result_Full all'usato temporanea in un processo.

2) Anche con la configurazione corrente, quando (sotto la mia interfaccia utente) mi sposto nella mia scheda che contiene DataGrid (il mio DataGrid si trova su una diversa TabPage), e cerco di aggiungere un nuovo elemento alla raccolta con quanto sopra menzionato codice, restituisce un errore dicendo: Il thread chiamante non può accedere a questo oggetto perché lo possiede un thread diverso., che è piuttosto strano, come InvokeOnUIThread non è altro che Dispatcher.Invoke(), che dovrebbe essere thread sicuro?

Qualsiasi aiuto sarebbe molto apprezzato.

EDIT: Questa è codice più:

Questo è il processo che io chiamo da BackgroundWorker:

public void ProcessFile() 
    { 
     var tmpError = new ObservableCollection<IP_DataRow>(); 
     var tmpFull = new ObservableCollection<IP_DataRow>(); 

     var _reader = new IP_ExcelReader(sExcelPath, ref tmpError, ref tmpFull); 
     string sResult = _reader.ReadExcelFile(); 
     if (sResult != string.Empty) 
     { 
      System.Windows.MessageBox.Show("Error processing selected Excel File!" + Environment.NewLine + Environment.NewLine + "Error message:" + Environment.NewLine + sResult); 
     } 

     foreach (var item in tmpError)//populates error list 
     { 
      IP_InvokeOnUIThread(() => 
      { 
       Result_Error.Add(item); 
      }); 
     } 

     foreach (var item in tmpFull)//populates full list 
     { 
      IP_InvokeOnUIThread(() => 
      { 
       Result_Full.Add(item); 
      }); 
     } 

     OnPropertyChanged("Result_Full"); 
     //OnPropertyChanged("Result_Error"); 

     iSelectedTabIndex = 1; 

    } 

Qui potete vedere, che devo creare raccolta temporanea tmpError, tmpFull dove raccolgo i miei dati. Alla fine del processo, copio manualmente i valori nelle mie raccolte principali legate a DataGrid. Vorrei cambiarlo, nel senso che i valori vengono copiati nella raccolta principale (non temporanei) durante il processo, in modo che l'utente possa vedere in tempo reale come i valori vengono aggiunti alla raccolta.

P.S.2: per un motivo noto a me, uno dei problemi ha mentito nella mia chiamata InvokeOnUIThread. Una volta ho cambiato da App.Current.Dispatcher.Invoke(action); a App.Current.Dispatcher.BeginInvoke(action); errore con .. thread diverso lo possiede fermato.

+0

quale thread possiede 'voce' e 'tmpFull'? – Pieter21

+0

* Quale dispatcher? * Dispatcher.Current è mantenuto in TLS, quindi ogni thread avrà il proprio dispatcher. È necessario accedere al dispatcher del thread dell'interfaccia utente. – Will

+0

Sto usando ** App.Current.Dispatcher.Invoke (azione); **. Ma io sono il dispatcher dell'interfaccia utente? Come posso accedervi allora? –

risposta

5
  1. È possibile utilizzare BackgroundWorker anziché thread per segnalare i progressi man mano che procede. Here è un semplice tutorial
  2. Credo che semplicemente chiamando Dispatcher userà thread di un contesto, che non è il thread UI nel tuo caso.Prova Application.Current.Dispatcher invece

Insomma, credo che si dovrebbe effettuare le seguenti operazioni:

  1. Creare ObservableCollection pubblico UI-thread e associarlo al DataGrid
  2. Creare un lavoratore sfondo. Imposta il reporting su true. Iscriviti agli eventi ReportProgress e DoWork.
  3. Esegui operaio asincrono
  4. Nel gestore DoWork creare un elenco e leggere alcuni valori. Quando raggiungi una certa quantità, diciamo cento, chiama il metodo (sender as BackgroundWorker).ReportProgress, passando l'evento args a questa raccolta che hai compilato.
  5. Nel gestore di avanzamento dei report, popola la tua ObservableCollection da un elenco che hai passato attraverso gli argomenti degli eventi.
  6. punti 4 - 5 vengono ripetuti fino a quando tutto è fatto
+0

Sto già utilizzando l'operatore in background. Il problema che ho è che non so come collegare la mia collezione temporanea alla collezione legata a DataGrid? Questo significa che sto solo popolando i miei valori, una volta che il mio vuoto di lettura Excel finisce. Condividerò più codice –

+0

Ho finito per passare BackgroundWorker come parametro ref alla mia funzione di lettura di Excel, e lì ho chiamato il metodo ProcessChanged, che ha fatto il trucco! –

Problemi correlati