2010-08-27 59 views
4

設置:帶進度條和標籤的主MDI表單。Winforms更新用戶界面異步模式 - 需要概括

代碼主要形式。

public delegate void UpdateMainProgressDelegate(string message, bool isProgressBarStopped); 

      private void UpdateMainProgress(string message, bool isProgressBarStopped) 
      { 
       // make sure we are running on the right thread to be 
       // updating this form's controls. 
       if (InvokeRequired == false) 
       { 
        // we are running on the right thread. Have your way with me! 
        bsStatusMessage.Caption = message + " [ " + System.DateTime.Now.ToShortTimeString() + " ]"; 
        progressBarStatus.Stopped = isProgressBarStopped; 
       } 
       else 
       { 
        // we are running on the wrong thread. 
        // Transfer control to the correct thread!     
        Invoke(new ApplicationLevelValues.UpdateMainProgressDelegate(UpdateMainProgress), message, isProgressBarStopped); 
       } 
      } 

子窗體

private readonly ApplicationLevelValues.UpdateMainProgressDelegate _UpdateMainForm; 
private void btnX_Click(object sender, EventArgs e) 
     { 
      _UpdateMainForm.BeginInvoke("StartA", false, null, null); 
      try 
      { 
       if(UpdateOperationA()) 
       { _UpdateMainForm.BeginInvoke("CompletedA", true, null, null); } 
       else 
       { _UpdateMainForm.BeginInvoke("CanceledA", true, null, null); } 
      } 
      catch (System.Exception ex) 
      { 
       _UpdateMainForm.BeginInvoke("ErrorA", true, null, null); 
       throw ex; 
      } 
     } 

其工作相當不錯,但對於N按鈕或N操作我不得不一次又一次地寫相同的代碼。有沒有什麼辦法可以推廣或更新用戶界面的其他更好的方法。

回答

4

這真的只是如果你的操作都可以表示爲一個單一的委託類型的簡單重構問題。例如: -

private void RunOperationWithMainProgressFeedback(
    Func<bool> operation, 
    string startMessage, 
    string completionMessage, 
    string cancellationMessage, 
    string errorMessage) 
{ 
    this._UpdateMainForm.BeginInvoke(startMessage, false, null, null); 
    try 
    { 
     if (operation.Invoke()) 
     { 
      this._UpdateMainForm.BeginInvoke(completionMessage, true, null, null); 
     } 
     else 
     { 
      this._UpdateMainForm.BeginInvoke(cancellationMessage, true, null, null); 
     } 
    } 
    catch (Exception) 
    { 
     this._UpdateMainForm.BeginInvoke(errorMessage, true, null, null); 
     throw; 
    } 
} 

private void btnX_Click(object sender, EventArgs e) 
{ 
    this.RunOperationWithMainProgressFeedback(
     this.UpdateOperationA, 
     "StartA", 
     "CompletedA", 
     "CanceledA", 
     "ErrorA"); 
} 

雖然可以使用字典來存儲參數值(如VinayC早期的回答表明),這是沒有必要的。就個人而言,我會避免這兩個可讀性和性能方面的原因,但情況因人而異...

+0

這似乎好多了,我會實施這種方法,並更新如果我什麼都瘋狂!! ..謝謝。 – 2010-09-05 20:11:20

2

您可以創建一個包含每個按鈕的相關詳細信息的字典/列表。這些細節將包括操作名稱&委託來調用操作等等。現在,您可以爲所有按鈕查找字典以獲取要執行的操作名稱和操作的通用事件處理程序。

另一種方法是創建按鈕,自定義按鈕繼承您的自定義按鈕可以擁有這些特性守住細節。根據你的喜好選擇。

+0

有趣。使用第一種方法,我猜想需要反射來通過存儲在字典中的名稱來調用方法。 – 2010-08-27 07:43:43

+0

不是,您可以將委託本身存儲在字典中。 – VinayC 2010-08-27 08:14:42

1

我累了一遍又一遍解決這個確切的同樣的問題,所以我寫了一個類的一般設置爲解決此問題。基本思想是這樣的:

  • 創建一個帶有你關心的字段的抽象Progress對象,比如statusMessage。

  • 創建一個抽象的Job對象。作業就像一個線程,但除了Main和Start之外,它還有一個方法UpdateProgress(Progress p)。 UpdateProgress將當前進度複製到p。它通常是唯一可以獲得鎖具的地方。

  • 在您的特定用途,子進步與根據需要添加字段。然後子類Job保存你想要做的事情,並實現UpdateProgress。

  • 在UI中,創建一個定時器,其主要電話的工作。 UpdateProgress然後更新ui。

定時器對於ui更新來說足夠好,並且採用pull-and-sync-ui模型比實現push-changes模型更簡單。 Pull-and-sync-ui避免了大量的交叉線程問題,並使UI進入怪異狀態。

獎金:讓你的進度條對象的INotifyProperyChanged,做數據綁定。 (這就是爲什麼你可能不想使用IDictionary)。

+0

看起來像一個相當沉重的方法..定時器,鎖,線程..可以提供一些僞代碼清晰? – 2010-09-03 10:45:45