2010-10-25 19 views
0

我正在編寫一個WinForm組件,我在其中啓動一個Task來執行實際處理並在延續中捕獲異常。從那裏我想在UI元素上顯示異常消息。如何在WinForm組件的UI線程上調用?

Task myTask = Task.Factory.StartNew (() => SomeMethod(someArgs)); 
myTask.ContinueWith (antecedant => uiTextBox.Text = antecedant.Exception.Message, 
        TaskContinuationOptions.OnlyOnFaulted); 

現在我得到一個跨線程異常,因爲任務試圖從顯然非UI線程更新UI元素。

但是,Component類中沒有定義Invoke或BeginInvoke。

如何從這裏開始?


UPDATE

而且,請注意,調用/的BeginInvoke/InvokeRequired不能從我的組件的派生類,因爲組件不爲他們提供。

回答

3

你可以給你的組件添加一個屬性,允許客戶端設置一個表單引用,你可以用它來調用它的BeginInvoke()方法。

這也可以自動完成,最好沒有人可以忘記。它需要一點設計時間的魔力,這是相當難以逾越的。我沒有自己想出來,我從ErrorProvider組件中獲得了它。值得信賴的來源和所有。將其粘貼到組件源代碼中:

using System.Windows.Forms; 
using System.ComponentModel.Design; 
... 
    [Browsable(false)] 
    public Form ParentForm { get; set; } 

    public override ISite Site { 
     set { 
      // Runs at design time, ensures designer initializes ParentForm 
      base.Site = value; 
      if (value != null) { 
       IDesignerHost service = value.GetService(typeof(IDesignerHost)) as IDesignerHost; 
       if (service != null) this.ParentForm = service.RootComponent as Form; 
      } 
     } 
    } 

當用戶將組件放在窗體上時,設計器會自動設置ParentForm屬性。使用ParentForm.BeginInvoke()。

+0

太棒了!它完美的工作!非常感謝你! – 2010-10-25 20:36:02

1

您可以使用委託來執行此操作。

delegate void UpdateStatusDelegate (string value); 


    void UpdateStatus(string value) 
    { 
     if (InvokeRequired) 
     { 
      // We're not in the UI thread, so we need to call BeginInvoke 
      BeginInvoke(new UpdateStatusDelegate(UpdateStatus), new object[]{value}); 
      return; 
     } 
     // Must be on the UI thread if we've got this far 
     statusIndicator.Text = value; 
    } 
+0

那麼,創建一個委託並調用它將使用UI線程? – 2010-10-25 19:52:32

+0

應該這樣做,未測試此代碼,但這是我在標準winforms中的工作方式 – jimplode 2010-10-25 19:56:04

+0

不幸的是,由於InvokeRequired方法在組件內不可用,因此這將不起作用。 – 2010-10-25 19:57:11