2012-08-11 34 views
3

我知道GUI組件不能用於不同的線程。所以你通常做一個方法,檢查InvokeRequired,然後打電話Invoke等,但這是很多代碼。有沒有辦法做到這樣的事情:MyEvent += myDelegate和這個myDelegate將從它被分配的線程執行? 爲什麼Invoke方法只能從Control類中獲得?我唯一的想法是使自己的方法像AddDelegate(委託..,控制c)或類似的東西。使用WinForms GUI控制線程安全事件

任何想法如何實現這一目標?

+0

嗯,是的 - 爲什麼'InvokeRequired'調用?當然這是必需的,爲什麼要檢查?在控制目標的問題上 - 我猜Control類和後代可以處理髮送/發佈給他們的消息。 – 2012-08-11 19:06:32

回答

2

我用一個相當簡單的方法:

private void execThreadSafeMethod(Control ctrl) 
{ 
    MethodInvoker method = (MethodInvoker) delegate 
    { 
     //Do something that you always wanted to do :) 
    } 
    if(ctrl.InvokeRequired == true) 
    { 
      ctrl.Invoke(method); 
    } 
    { 
      method.Invoke(); 
    } 
} 
4

爲了避免這種repeatitive代碼,我通常創建一個類以分離此邏輯。當應用程序啓動時,我初始化這個類並在整個應用程序中使用它。優點是它可以在控件之外使用。

public static class UI 
{ 
    private static Control internalControl; 

    public static void Initialize(Control control) 
    { 
     internalControl = control; 
    } 

    public static void Invoke(Action action) 
    { 
     if (internalControl.InvokeRequired) 
     { 
      internalControl.Invoke(action); 
     } 
     else 
     { 
      action(); 
     } 
    } 
} 

初始化時,主窗體初始化:

UI.Initialize(this); 

用法:

UI.Invoke(() => { this.Text = "Test"; }); 
+0

所以如果我有很多UserControls,那麼我需要在每個UserControl中初始化類? – 2013-11-28 13:31:04

1

您在使用.NET 4.0?如果是這樣,你可以使用異步任務。

您可以從創建控件的主線程的同步上下文創建TaskScheduler。

var uiTaskScheduler = TaskScheduler.FromCurrentSynchronizationContext(); 

然後,您可以在後臺線程上運行的任何方法中使用此更新來更新主線程上的任何控件。

Task.Factory.StartNew(
    () => { MessageBox.Show("Message from separate thread.") }, 
    CancellationToken.None, 
    TaskCreationOptions.None, 
    uiTaskScheduler); 
1

一直在等待找我的方法,但我沒有看到它(希望我讀題吧)

這是我如何處理調用在單獨的線程:

this.Invoke((MethodInvoker)delegate() { /*whatever I need done*/ }); 

這是很好的,因爲你可以保持你的代碼在適用的地方,而不是跳來跳去

this.Invoke((MethodInvoker)delegate() { 
    //here is some code I need to run on the main thread 
    //usually making a label visible or some other bs 
    //might want to resize my form or update a list box, who knows 
});