代码之家  ›  专栏  ›  技术社区  ›  smwikipedia

如何从后台线程安全地更新WinForm UI?[副本]

  •  0
  • smwikipedia  · 技术社区  · 7 年前

    我有2个winforms:

    • 表格2

    表格1是主要表格。Form1打开Form2。在表格2中 Load 事件处理程序,则启动一个新的后台工作线程。当工作线程完成时,它将通知UI线程更新Form2。

    用户可以在工作线程仍在运行时关闭Form2

    我打算用一个标志来表示Form2的存在。每次更新UI时,都会检查标志以确保Form2存在。但是这个 检查并采取行动 模式无法处理种族密码。因为表单可能已关闭 支票通过了,但是 之前 执行UI更新操作。

    那么有什么方法可以解决这个问题吗?

    private void StartComputeGraphWorker()
    {// this runs on the UI thread.
        try
        {
            this.generationFinished = false;
            DisableAllControls(); //prevent user input while some background work is underway.
            StartShowProgressMarquee();
            ThreadStart d = new ThreadStart(WorkerStartWrapper);
            worker = new Thread(d);
            worker.IsBackground = true;
            worker.Start();
        }
        catch (Exception ex)
        {
            Logger.LogMessage(Logger.LogLevel.Error, ex.Message);
            EnableAllControls();
            StopShowProgressMarquee();
        }
    }
    
    
    private void NotifyUI(Boolean suceess)
    {
        if (suceess)
        {
            // this is on the secondary illustration form. it may NOT exist by now.
            if (!this.formClosed)
            {//race conditions here
                this.Invoke(new MethodInvoker(ShowGraphDataInUIThread));
            }
            else//the form has been closed, we have no place to show the graph, just return.
            {
                return;
            }
        }
        else
        {
            // this logs to the main input form, it always exists.
            Logger.LogMessage(Logger.LogLevel.Warning, "Graph generation failed."); 
        }
    }
    
    private void WorkerStartWrapper()
    {
        try
        {
            RenderGraphWorker();
            NotifyUI(true);
        }
        catch (Exception ex) // ThreadAbortException or Other Exceptions
        {
            Logger.LogMessage(Logger.LogLevel.Warning, ex.Message);
            NotifyUI(false);
        }
    }
    

    添加1

    我检查了以下线程:

    How to update the GUI from another thread in C#?

    这不完全一样。我的表格可能会消失。这不仅仅是关于跨线程控制更新。

    使用BackgroundWorker方法,在Form2结束事件中取消订阅RunWorkerCompleted事件可以解决我的问题。

    1 回复  |  直到 7 年前
        1
  •  0
  •   smwikipedia    7 年前

    取消订阅 方法看起来不错。但实际上可能不是。

    有一个 当我取消订阅时,代码可能正在已完成的事件处理程序中运行。 因此,取消订阅不会阻止它操作可能不存在的表单。

    我认为我仍然应该坚持标准的BGW范式,并以其他方式解决这个问题。

    • 单击 Cancel 按钮
    • 关闭表单。

    如果用户单击 Cacncel 按钮,我将在 取消 之前 调用 bgw.CancelAsync()

    this.label1.Text = "Operation Cancelled";
    bgw.CancelAsync()
    

    此时,UI是 存在。

    如果用户关闭表单,我只需调用 bgw。CancelAsync() BGW.DoWork() 将轮询并找到此信号并停止执行。我需要 隐含意图

    对于这两种取消场景,BGW complete事件处理程序不包含对取消结果的UI操作。

    总之,让BGW完成其生命周期。