2010-11-16 48 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