2009-08-18 47 views
7

所以我有一個任務,可以由我的GUI執行,將拉動信息填充SQL數據庫查詢響應的ViewModel。 假設我想開始這個任務,並讓我的GUI自由地繼續其他事情,並在此期間播放「搜索」動畫,什麼是在WPF/MVVM中這樣做的正確方法?我假設你需要啓動一個異步過程並設置一個綁定到啓動動畫故事板的數據觸發器的布爾。 但是我用什麼來啓動這個過程呢?線?我對WPF還很陌生,只是想確保我使用的是正確的類。正確的方式在WPF MVVM啓動線程查找任務

回答

8

我使用BackgroundProcess線程來做這樣的事情。

下面是MSDN的鏈接在此:http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.aspx

與此有關的更多細節。

您有三個事件與您的BackgroundProcess對象相關聯:DoWork,ReportProgress和WorkCompleted。

現在,要使用它並將其與observablecollection一起使用,您需要告訴BackgroundProcess對象能夠REPORT PROGRESS(這是一個布爾屬性,我總是明確設置的,以及允許取消)。

現在開始一個過程,您將調用RunWorkerAsync方法。如果需要傳遞數據(如果需要多個值,則創建一個要傳遞到RunWorkerAsync的結構體),此方法有能力接受OBJECT變量。

RunWorkerAsync觸發DoWork事件,因此控制權轉交給您的DoWork事件處理程序。這裏是(消毒)從我利用它放在代碼:

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 

這裏發生的事情,就是我正從我的數據層的DataTable,然後同時這backgroundprocess沒有被取消,我遍歷數據表,當我構建一個新的數據對象時,我將該對象報告爲正在構建。

現在,在我的ProgressChanged事件處理程序(ReportProgress方法引發ProgressChanged事件)中,控件返回到UI線程的手中,因此我可以執行諸如影響UI之類的操作,並將報告的元素添加到ObservableCollection中。

最後,在我的WorkedCompleted事件處理程序中(當DoWork事件處理程序方法運行完成時引發相應的事件),我檢查是否取消了進度(這有時意味着我想轉儲ObservableCollection)和I可能會也可能不會影響到UI(如刪除「搜索」的動畫。

+0

嘗試這樣的CollectionChanged事件,似乎鎖定了我的GUI壽... – Firoso 2009-08-18 18:51:48

+0

如果鎖定了您的GUI,你就錯了。 – 2009-08-18 20:03:24

+0

我做錯了,去了線索,看着這個,但我真的很喜歡這個。 – Firoso 2009-08-18 20:30:58

2

你可以開始一個新的ThreadBackgroundWorker明確,或使用ThreadPool。我不知道在MVVM這樣做的任何建議的方法...

如果您的異步操作正在填充綁定到控件的ObservableCollection,請注意您無法添加項目在不同的線程上。您需要在控件的調度程序線程上執行此操作。或者你也可以使用this collection,這引起了足夠的線程

+0

我想我在這裏的Observable集合有一個相關的問題,我的代碼是基於MVVM的,所以我的工作人員正在對視圖模型進行更改...該視圖模型綁定到UI元素...所以它鎖定了。 – Firoso 2009-08-18 19:04:12

+0

在標量屬性上進行綁定可以在線程中正常工作,更改通知會自動在右側線程中編組。對於集合,它不受支持。看到我給你一個可能的解決方案的鏈接 – 2009-08-19 00:13:54

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

t.Start();