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

从后台线程结果更新WinForms UI

  •  4
  • Sergey  · 技术社区  · 17 年前

    这可能是一个愚蠢的问题,但我在stackoverflow上找不到答案。

    我在一个WinForm应用程序中有一个按钮点击事件,它运行一个线程来计算一个结果并显示在一个窗体中。

    当线程计算出结果时,如何更新窗体UI?

        private void btnRequestR2Approval_Click(object sender, EventArgs e)
        {
            if (User.IsLogged)
            {
                ValidationResults results = new ValidationResults();
                results.Show();
    
                Logger log = Logger.Instance();
                Logger.NewLogAddedHandler messageDelegate = new Logger.NewLogAddedHandler(results.NewLogMessage);
    
                if (!log.IsEventHandlerRegistered())
                {
                    log.NewLogAdded += messageDelegate;
                }
    
                ThreadStart operation = new ThreadStart(ValidateAndSubmit);
                Thread theThread = new Thread(operation);
                theThread.Start();
    
            }
            else
            {
                MessageBox.Show("Please login");
            }
    
        }
    

    谢谢你

    4 回复  |  直到 17 年前
        1
  •  13
  •   Don Kirkby    14 年前

    在WinForms中执行后台任务的最简单技术是使用 BackgroundWorker .

    • 把它放到表格上。
    • 把事件联系起来。至少,使用 DoWork . 你可能也会想要 RunWorkerCompleted .
    • 把你的背景任务写在 道沃克 事件。
    • 在中写入任何用户界面更改 运行工作已完成 事件。
    • 呼叫 backgroundWorker1.RunWorkerAsync(); 为了启动这个过程,可能是来自某个按钮处理程序。

    使用后台工作人员可以避免所有恼人的线程处理和isinvokerequired的内容。

    这里有一个更详细的 how-to article .

        2
  •  2
  •   Jeff Fritz    17 年前

    尝试将BeginInvoke与回调操作一起使用…这会将您的调用推送到另一个线程,并在线程完成时调用您选择的方法:

    private void btnRequestR2Approval_Click(object sender, EventArgs e)
    {
        if (User.IsLogged)
        {
            ValidationResults results = new ValidationResults();
            results.Show();
    
            Logger log = Logger.Instance();
            Logger.NewLogAddedHandler messageDelegate = new Logger.NewLogAddedHandler(results.NewLogMessage);
    
            if (!log.IsEventHandlerRegistered())
            {
    
                log.NewLogAdded += messageDelegate;
            }
    
            ThreadStart operation = new ThreadStart(ValidateAndSubmit);
            operation.BeginInvoke(MyCallBack, this);
        }
        else
        {
            MessageBox.Show("Please login");
        }
    
    }
    
    private static void MyCallBack(IAsyncResult ar) {
      ((MyForm)ar.AsyncState).Refresh();
    }
    
        3
  •  2
  •   Dour High Arch    17 年前

    我假设,这个问题非常不清楚:

    1. 您运行的是Windows WinForms应用程序,而不是ASP.NET网页。
    2. 您希望触发可能需要很长时间的后台计算,并且不希望在发生这种情况时阻止您的UI。
    3. 当后台计算完成后,您希望您的UI获得某种结果。
    4. 当后台计算向您的用户界面提供结果时,您希望退出后台计算。

    如果是这样,则应该使用异步委托,而不是线程。例如:

    string SleepAndReturnParam(string param1)
    {
        System.Threading.Thread.Sleep(10000);
        return param1;
    }
    
    // Declare a delegate matching our async method.
    public delegate string DelegateWithParamReturningString(string param1);
    
    
    private void button1_Click(object sender, EventArgs e)
    {
        var myDelegate = new DelegateWithParamReturningString(SleepAndReturnParam);
    
        // Run delegate in thread pool.
        myDelegate.BeginInvoke("param1",
            OnCallBack, // Completion callback
            this); // value to pass to callback as AsyncState
    }
    
    
    private void OnCallBack(IAsyncResult ar)
    {
        // first cast IAsyncResult to an AsyncResult object
        var result = ar as System.Runtime.Remoting.Messaging.AsyncResult;
    
        // grab the delegate
        var myDelegate = result.AsyncDelegate as DelegateWithParamReturningString;
    
        // Exit delegate and retrieve return value.
        string returnValue = myDelegate.EndInvoke(ar);
    
        // Declare an anonymous method to avoid having to define
        // a method just to update a field.
        MethodInvoker formFieldUpdater = delegate
        {
            formTextField.Text = returnValue;
        };
    
        // Winforms controls must be modified on the thread
        // they were created in.
        if (formTextField.InvokeRequired)
            Invoke(formFieldUpdater);
        else
            formFieldUpdater();
    }
    
        4
  •  0
  •   David McEwing    17 年前

    你也可以 1。做一个 theThread.Join() 它会阻塞调用线程。 2。将第一个线程传递给第二个线程,这样它就可以向主线程进行回调,而主线程需要执行 Invoke() 所以它可以重新绘制表单。

    不过我很好奇。您使用的是ASP.NET(WebForms)还是WinForms?如果你想在网络上做到这一点,那么你需要一个完全不同的方法。

    推荐文章