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.
quale thread possiede 'voce' e 'tmpFull'? – Pieter21
* Quale dispatcher? * Dispatcher.Current è mantenuto in TLS, quindi ogni thread avrà il proprio dispatcher. È necessario accedere al dispatcher del thread dell'interfaccia utente. – Will
Sto usando ** App.Current.Dispatcher.Invoke (azione); **. Ma io sono il dispatcher dell'interfaccia utente? Come posso accedervi allora? –