2009-08-18 4 views
7

Mam więc zadanie, które może być wykonane przez mój GUI, który będzie pobierał informacje w celu wypełnienia obiektu ViewModel za pomocą odpowiedzi na zapytanie SQL. Załóżmy, że chcę uruchomić to zadanie i utrzymywać moje gui za darmo, aby móc wykonywać inne czynności:, aw międzyczasie odtwarzam animację "przeszukiwania", jaki jest właściwy sposób wykonania tej czynności w WPF/MVVM? Zakładam, że musisz rozpocząć proces asynchroniczny i ustawić bool związany z datatriggerem, który uruchamia scenorię animacji. Ale czego używam do rozpoczęcia procesu? Wątek? Jestem wciąż nowy w WPF i chcę tylko upewnić się, że używam odpowiednich klas dostępnych dla mnie.Właściwy sposób w WPF MVVM, aby uruchomić zadanie wyszukiwania z gwintem

Odpowiedz

8

Używam wątku BackgroundProcess do robienia takich rzeczy.

Oto link do MSDN na ten temat: http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.aspx

Dodatkowe szczegóły związane z tym.

Masz trzy ZDARZENIA powiązane z twoim obiektem BackgroundProcess: DoWork, ReportProgress i WorkCompleted.

Teraz, aby użyć tego - i użyć go z możliwością obserwowania - powinieneś powiedzieć obiektowi BackgroundProcess, aby mógł ZGŁOSIĆ POSTĘP (jest to właściwość boolowska, którą zawsze jawnie ustawiam, wraz z umożliwia anulowanie).

Teraz, aby rozpocząć proces, należy wywołać metodę RunWorkerAsync. Ta metoda ma możliwość akceptowania zmiennej OBJECT w przypadku, gdy musisz przekazać jej dane (jeśli chcesz uzyskać więcej niż jedną wartość, utwórz strukturę do przekazania do RunWorkerAsync).

RunWorkerAsync wystrzeliwuje zdarzenie DoWork, więc prześlijcie głowami do swojej obsługi zdarzeń DoWork. Oto (odkażane) Kod skąd mam wykorzystując go:

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 

Co tu się dzieje, jest to, że jestem coraz DataTable z mojego warstwy danych, a następnie, gdy ten backgroundprocess nie jest anulowane, jestem chodzenie po tabeli danych, a kiedy buduję nowy obiekt DataObject, zgłaszam ten obiekt jako budowany.

Teraz w mojej procedurze obsługi zdarzenia ProgressChanged (metoda ReportProgress podnosi zdarzenie ProgressChanged) kontrola jest ponownie w rękach wątku interfejsu użytkownika, dzięki czemu mogę np. Wpływać na interfejs użytkownika i dodawać element, który zgłaszam do ObservableCollection.

Wreszcie, w mojej procedurze obsługi zdarzeń WorkedCompleted (której odpowiednie zdarzenie jest wywoływane, gdy metoda obsługi zdarzenia DoWork jest uruchamiana do zakończenia) sprawdzam, czy mój postęp został anulowany (co czasami oznacza, że ​​chcę zrzucić ObservableCollection) i może lub nie może wpłynąć na UI (takie jak usuwanie „wyszukiwanie” animacji.

+0

próbował to, zdaje się zamknąć moje GUI tho ... – Firoso

+0

jeśli zablokuje swoje GUI robisz to źle. –

+0

zrobiłem to źle, poszedłem do wątku, patrząc na to jednak naprawdę to lubię. – Firoso

2

można rozpocząć nowy Thread lub BackgroundWorker jawnie lub użyć ThreadPool. nie jestem świadom wszelkich zalecanych sposobów na osiągnięcie tego w MVVM ...

Jeśli operacja asynchroniczna wypełnia jednostkę ObservableCollection powiązaną z formantem, należy pamiętać, że nie można dodać elementy do niego w innym wątku. Musisz to zrobić w wątku kontrolnego kontrolera. Lub można również skorzystać this collection, który zgłasza zdarzenie CollectionChanged na odpowiednim wątku

+0

Myślę, że mam problem z tym związany do kolekcji Observable, mój kod jest oparty na MVVM, a więc mój pracownik wprowadza zmiany w modelu widoku ... ten model widoku jest związany z elementami interfejsu użytkownika ... więc blokuje się . – Firoso

+0

Wiązanie na właściwościach skalarnych działa dobrze we wszystkich wątkach, powiadomienie o zmianie jest automatycznie kierowane na właściwy wątek. W przypadku kolekcji nie jest obsługiwany. Zobacz link podany przez ciebie dla możliwego rozwiązania –

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

t.Start(); 
Powiązane problemy