代码之家  ›  专栏  ›  技术社区  ›  Ohad Schneider

利用BackGroundWorker跨线程调用Winforms控件上的GUI操作?

  •  1
  • Ohad Schneider  · 技术社区  · 14 年前

    灵感来源于我在多线程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!"));    
    }
    

    当然,这不是最经济的方法(让线程保持这样的活力),但如果它有效,而且我没有遗漏任何东西,那肯定是我见过的最简单的方法。

    非常感谢您的反馈!

    1 回复  |  直到 8 年前
        1
  •  6
  •   ukalpa    7 年前

    没有必要为此而打开线程。简单使用 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!"));    
    }