2010-11-16 57 views
1

靈感來自我自己的多線程應用程序的WinForms經驗,以及這樣的問題利用BackGroundWorker對Winforms控件上的GUI操作進行跨線程調用?

,我想出了一個非常簡單的模式,它的合理性我會喜歡驗證。

基本上我創建(並在整個應用程序的生命週期中運行)一個BGW,其唯一目的是調用請求的同步。試想一下:

public MainForm() 
{ 
    InitializeComponent(); 
    InitInvocationSyncWorker(); 
} 

private void InitInvocationSyncWorker() 
{ 
    InvocationSync_Worker.RunWorkerAsync(); 
} 

private void InvocationSync_Worker_DoWork(object sender, DoWorkEventArgs e) 
{ 
    Thread.Sleep(Timeout.Infinite); 
} 

void InvokeViaSyncWorker(Action guiAction) 
{ 
    InvocationSync_Worker.ReportProgress(0, guiAction); 
} 

private void InvocationSync_ProgressChanged(object sender, ProgressChangedEventArgs e) 
{ 
    if (IsDisposed) return; //we're in the GUI thread now, so no race condition right? 

    var action = (Action) e.UserState; 
    action(); 
} 

public void SomeMethodCalledFromAnyThread() //Sample usage 
{ 
    InvokeViaSyncWorker(() => MyTextBox.Text = "Hello from another thread!"));  
} 

當然,這不是最經濟的方式(保持一個線程活着那樣),但如果它的作品,我都沒有錯過什麼,可以肯定的是我見過的最簡單的。

反饋非常感謝!

+0

有趣的問題:) – Pedery 2010-11-16 02:05:03

+0

我也這麼認爲:)希望這是一個好兆頭,它沒有被證僞又 – 2010-11-16 08:46:12

回答

6

沒有必要爲此打開一個線程。只需使用SynchronizationContext,就像這樣:

private readonly SynchronizationContext _syncContext; 

public MainForm() 
{ 
    InitializeComponent(); 

    _syncContext = SynchronizationContext.Current; 
} 

void InvokeViaSyncContext(Action uiAction) 
{ 
    _syncContext.Post(o => 
    { 
     if (IsHandleCreated && !IsDisposed) uiAction(); 
    }, null); 
} 

public void SomeMethodCalledFromAnyThread() //Sample usage 
{ 
    InvokeViaSyncContext(() => MyTextBox.Text = "Hello from another thread!"));  
} 
+0

謝謝!請注意,在這裏使用'Post','BeginInvokeViaSyncContext'應該是一個更合適的名稱。我將創建2個重載,其中一個像上面那樣(異步),另一個使用'Send'(同步) – 2010-11-19 17:28:36