利用 BackGroundWorker 在 Winforms 控件上跨线程调用 GUI 操作?
受到我自己使用多线程 Winforms 应用程序的经验以及诸如
我想出了一个非常简单的模式,我想验证其合理性。
基本上,我正在创建(并在应用程序的整个生命周期中运行)一个 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!"));
}
当然,这不是最经济的方法(像这样保持线程存活),但如果它有效并且我没有错过任何东西,那么它肯定是我见过的最简单的方法。
非常感谢您的反馈!
Inspired by my own experience with multithreaded Winforms applications, as well as questions such as
- Avoiding the woes of Invoke/BeginInvoke in cross-thread WinForm event handling?
- Avoid calling Invoke when the control is disposed
I've come up with a very simple pattern, whose soundness I would like to verify.
Basically I'm creating (and running throughout the application's lifetime) a BGW whose sole purpose is the synchronization of invoke requests. Consider:
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!"));
}
Granted, it's not the most economical of approaches (keeping a thread alive like that), but if it works and I haven't missed anything, it sure is the simplest I've seen.
Feedback is highly appreciated !
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
没有必要为此打开一个线程。只需使用
SynchronizationContext
,如下所示:There's no need to open a thread just for that. Simply use
SynchronizationContext
, like so: