2009-08-18 5 views
7

Quindi ho un compito che può essere preformato dalla mia GUI che estrarrà informazioni per popolare un ViewModel con risposta alle query del database SQL. Supponiamo di voler iniziare questa attività e di mantenere la mia gui libera per procedere con altre cose e, nel frattempo, riprodurre un'animazione di "ricerca", qual è il modo corretto di farlo in WPF/MVVM? Suppongo che sia necessario avviare un processo asincrono e impostare un bool legato a un datatrigger che avvia lo storyboard dell'animazione. Ma cosa utilizzo per avviare il processo? Filo? Sono ancora nuovo a WPF e voglio solo assicurarmi che sto usando le classi giuste disponibili per me.Modo corretto in WVF MVVM per avviare un'attività di ricerca con thread

risposta

8

Uso il thread BackgroundProcess per fare cose come questa.

Ecco un link a MSDN su questo: http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.aspx

Ulteriori dettagli relativi a questo.

Sono presenti tre EVENTI associati all'oggetto BackgroundProcess: DoWork, ReportProgress e WorkCompleted.

Ora, per usare questo - e per usarlo con una raccolta di dati osservabile - vorrete dire all'oggetto BackgroundProcess di essere in grado di REPORT PROGRESS (questa è una proprietà booleana che ho sempre esplicitamente impostato, insieme al consente la cancellazione).

Ora per avviare un processo, chiameremo il metodo RunWorkerAsync. Questo metodo ha la capacità di accettare una variabile OBJECT nel caso in cui sia necessario passarlo (se si desidera più di 1 valore, creare una struct da passare in RunWorkerAsync).

RunWorkerAsync spegne l'evento DoWork, quindi il controllo passa al gestore di eventi DoWork. Ecco il codice (sterilizzata) da dove sto utilizzandolo:

Dim dt As System.Data.DataTable 
dt = da.GetDataTable(sql, System.Data.CommandType.Text, params) 
For Each row As System.Data.DataRow In dt.Rows 
    If loadQuestionsWorker.CancellationPending Then 
     e.Cancel = True 
     Exit Sub 
    End If 
    Dim item As New DataObject 
    // Assign Item Values 
    backgroundProcessObject.ReportProgress(1, item) 
Next 

Quello che sta succedendo qui, è che sto ricevendo un DataTable dal mio livello dei dati, e quindi mentre questo backgroundprocess non viene annullata, io sono camminando sulla tabella dati, e quando costruisco un nuovo DataObject, riporto l'oggetto come costruito.

Ora, nel mio gestore di eventi ProgressChanged (il metodo ReportProgress genera l'evento ProgressChanged) il controllo è di nuovo nelle mani del thread dell'interfaccia utente, quindi posso fare cose come avere un impatto sull'interfaccia utente e aggiungere l'elemento che sto segnalando a ObservableCollection.

Infine, nel mio gestore di eventi WorkedCompleted (il cui evento corrispondente viene generato quando il metodo del gestore di eventi DoWork è in esecuzione), controllo se i miei progressi sono stati annullati (che a volte significa che voglio scaricare ObservableCollection) e I può o non può avere un impatto l'interfaccia utente (come la rimozione di un'animazione "ricerca".

+0

provato questo, sembra chiudere la mia GUI tho ... – Firoso

+0

se si blocca la vostra interfaccia grafica si sta facendo male. –

+0

stavo sbagliando, sono andato al thread, guardando questo però mi piace molto questo. – Firoso

2

È possibile avviare una nuova Thread o BackgroundWorker esplicitamente, o utilizzare un ThreadPool. io non sono a conoscenza di alcun modo consigliato di fare questo in MVVM ...

Se l'operazione asincrona sta compilando un ObservableCollection associato a un controllo, notare che non è possibile aggiungere articoli su un thread diverso. È necessario farlo sul thread del dispatcher del controllo. Oppure si può anche usare this collection, che genera l'evento CollectionChanged sul filo adeguata

+0

Penso di avere un problema correlato qui alla raccolta Observable, il mio codice è basato su MVVM e quindi il mio operatore sta apportando delle modifiche al modello di vista ... quel modello di vista è legato agli elementi dell'interfaccia utente ... quindi si blocca . – Firoso

+0

Il binding su proprietà scalari funziona bene su thread, la notifica di modifica viene automaticamente impostata sul thread corretto. Per le raccolte, non è supportato. Vedi il link che ti ho dato per una possibile soluzione –

1
var t = new Thread((ThreadStart)delegate 
{ 
    DoWork(...) 
    Dispatcher.BeginInvoke((Action)delegate 
    { 
      SomethingOntheUiThread(...) 
      FinishedWork(...); 
    } 
}); 

t.Start(); 
Problemi correlati