2011-01-25 25 views
7

假設我們有一個具有分層體系結構的應用程序。在視圖上我們使用MVC或MVVM。該模型被視爲領域,它有很好的商業邏輯。如何從業務/模型類發送進度更新?

現在讓我們說我們有,在模型中,需要一些時間的方法。例如,必須對每個對象項目進行復雜的計算或處理。

在UI中,我們想顯示進度條和將顯示計算(例如,使用所有的處理歷史列表框)的當前步驟文本。

你會怎麼做?如何從模型發送進程的進度信息以及如何連接Controller或ViewModel以便更新進程?

回答

5

我經常通過以下方式實現這一點。我的業務層流程需要很長時間才能運行,因此每隔一段時間就會引發一些事件,以表明它正在實現特定的「里程碑」。你決定通過事件發送什麼里程碑以及其中有多少。如果你的耗時過程是一個簡單的循環,你可以選擇例如循環中每10%的項目一次又一次地引發相同的事件。如果它是一個具有不同階段的流程,那麼隨着每個階段的完成,您可以選擇提出不同的事件。

現在,你的表現層訂閱這些事件和行爲的結果,更新進度條,文本或什麼的。

這種機制是很好的,因爲:

  1. 業務層保持獨立的東西可以去了在表示層。
  2. 這是很容易延長雙向通信。您可以輕鬆地更改事件,以便表示層(或任何其他訂戶)可以返回取消標誌,以便業務層知道必須取消長時間運行的進程。
  3. 它允許同步或異步工作。也就是說,您可以在阻止調用(即您的演示文稿和業務層共享相同線程)或非阻塞調用(即您的業務層使用後臺工作線程)時使用它。在後一種情況下可以使用System.ComponentModel.BackgroundWorker類,但如果您想要引發多種類型的事件,則不太好。

希望這會有所幫助。

+0

感謝您的非常完整的答案。我認爲事件是一個非常技術性的問題,在業務層中沒有它的地位。但最終必須有一種方法來發送有關過程如何進行的信息。 – Gimly 2011-02-02 14:01:38

0

你需要探索觀察者模式(http://en.wikipedia.org/wiki/Observer_pattern)。這是桌面應用程序非常普遍的做法。這對Web來說有點複雜。您可能還想研究Comet [http://en.wikipedia.org/wiki/Comet_(programming)],看看它是如何爲Web完成的。

+0

視圖模型和視圖(Observer模式)之間的數據綁定我想過當然觀察者模式,因爲這是很常見的.NET。但我不覺得這是對的,因爲這意味着在這個行業有技術性的東西,我覺得有點不對。 – Gimly 2011-01-26 09:18:48

0

我採取了以下方法來處理類似的情況。這個觀點有一個可能需要很長時間的行動,我想定期展示進展。長時間的行動被推到另一個班級,工人。某些用戶操作會在TestViewModel中啓動對DoSomething的調用。

TestView.xaml

... 
<!-- Progress bar --> 
<ProgressBar Visibility="Visible" Height="10" Value="{Binding SomeValue}"/> 
... 

TestViewModel。CS擴展BaseViewModel,BaseViewModel只是實現INotifyPropertyChanged

... 
private void DoSomething(){ 
    Worker worker = new Worker(); 
    worker.ProgressChanged += new EventHandler<WorkerEventArgs>(OnProgressChanged); 
    worker.Start(); 
} 

private void OnProgressChanged(object sender, WorkerEventArgs args){ 
    SomeValue = args.Progress; 
} 

private const String SomeValuePropertyName = "SomeValue"; 
private double someValue; 
public double SomeValue 
{ 
    get 
    { 
     return someValue; 
    } 
    set 
    { 
     if (someValue == value) 
     { 
      return; 
     } 
     someValue = value; 
     NotifyPropertyChanged(SomeValuePropertyName); 
    } 
} 
... 

Worker.cs

... 
public event EventHandler<WorkerEventArgs> ProgressChanged; 
public void Start(){ 
    //This will take a long time. Periodically call NotifyProgress 
} 

private void NotifyProgress() 
{ 
    if (ProgressChanged != null) 
    { 
     double progress = ...; //calculate progress 
     ProgressChanged(this, new WorkerEventArgs(progress)); 
    } 
} 
... 

WorkerEventArgs.cs

public class WorkerEventArgs : EventArgs 
{ 
    public double Progress { get; private set; } 

    public WorkerEventArgs(double progress) 
    { 
     Progress = progress; 
    } 
} 
2

我會建議尋找在System.ComponentModel命名空間提供的BackgroundWorker類。

的背景工人提供您需要在一個單獨的線程運行密集型操作的方法,以及接收狀態更新(通過ReportProgress,ProgressChangedRunWorkerCompleted)。

我其實親自嘗試在網絡環境中使用BackgroundWorker,以運行計劃任務。我決定發佈迄今爲止在Codeplex上完成的工作。我覺得我的代碼的精神可能對你的情況有用。 'Web Scheduled Task Framework' codeplex project

如果您選擇下載該項目,您將會看到我如何在ScheduledTaskRunner類中使用BackgroundWorker類。我的實現不會將進度事件附加到工作人員,但這樣做很容易。另外,我當前的實現重點關注在給定時間間隔內運行任務,但將其修改爲更多「按需」處理隊列不會很困難。我甚至可以補充說,現在我認爲它是一個功能:)

假設你遵循上面我的代碼的方法,這將是很容易創建一個操作在你的控制器被開除將檢查列表'任務'(或者您感興趣的特定任務),並將信息報告爲某種ActionResult。設置一些JavaScript來按指定的時間間隔輪詢動作,你就會有進步!

祝你好運,讓我知道如果你有任何關於我的代碼的問題。

1

根據您的其他意見,您試圖儘可能保持業務層的清潔。

然後模型 - 視圖 - 視圖模型方法可能適合:http://en.wikipedia.org/wiki/Model_View_ViewModel

由於calcualtion完成後,你把事件已經取得了進展。

這些事件在ViewModel中被捕獲,並且更新了進度量。

視圖被更新,由於