【问题标题】:BeginInvoke callback functionBeginInvoke 回调函数
【发布时间】:2012-06-08 13:43:11
【问题描述】:

我有一个 c# .NET winforms 应用程序进行此异步调用:

simpleDelegate.BeginInvoke(null, null);

代理正在调用我的函数,并且一切正常。问题是,在工作线程上的函数完成后,我需要主线程来更新我的 winform 上的一些控件。如果工作线程试图更新这些控件,.NET 就会崩溃。但我需要主线程保持对用户操作的响应,然后仅在工作线程完成调用异步函数后调用我的函数 UpdateFormAfterServerCall()。

如果您能给我一个简洁的代码示例,而不是抽象地解释如何做到这一点,我将不胜感激。我已经阅读了一百个解释,只是无法正确地将它们连接在一起。

注意:在 BeginInvoke 之前我有:

simpleDelegate = new MethodInvoker(CallServer);

【问题讨论】:

    标签: c# .net winforms multithreading .net-4.0


    【解决方案1】:

    如果您想更新另一个线程拥有的 GUI,请从不同的线程使用 MethodInvoker

    if(control.InvokeRequired)
    control.Invoke( (MethodInvoker) ( ()=> updating_function() ) );
    else
    updating_function();
    

    【讨论】:

      【解决方案2】:

      你可以使用BackgroundWorker:

      BackgroundWorker bw = new BackgroundWorker();
      
      string result = null;
      
      bw.DoWork += (s, e) =>
      {
          // Executes on background thread.
          // UI remains responsive to user activity during this time.
          result = CallServer();
      };
      
      bw.RunWorkerCompleted += (s, e) =>
      {
          // Executes on UI thread upon completion.
          resultTextBox.Text = result;
      };
      
      bw.RunWorkerAsync();
      

      【讨论】:

      • 我尝试了您的代码,但仍然收到关于无法从工作线程更新控件的相同错误。你的代码应该放在哪里?在哪个功能?是在工作线程还是主线程中执行?
      • 上面的代码应该从 UI 线程运行,通常在一些事件处理程序中。 BackgroundWorker 将首先在工作线程上执行 DoWork 委托,让 UI 保持响应;完成后,它将在 UI 线程上执行RunWorkerCompleted
      【解决方案3】:

      Control 类(Form 也是Control)有一个Invoke 方法,您可以从任何线程调用它以在GUI 线程上执行代码。

      此外,Control 有一个方便的InvokeRequired 属性,可以通知您是否已经在 GUI 线程上。例如,您可以在表单中创建以下方法:

      public class MyForm
      {
          // ...
          public void UpdateMe()
          {
              if (InvokeRequired)
              {
                  Invoke(new Action(UpdateMe));
                  return;
              }
      
             // Code to update the control, guaranteed to be on the GUI thread
          }
      }
      

      【讨论】:

      • 谢谢...但我很困惑。您正在从 UpdateMe 内部调用 UpdateMe。这不会造成无限循环吗?什么应该调用 UpdateMe,一旦我在工作线程中运行的函数完成后,如何触发它被调用?
      • InvokeRequired 仅当在 UI 线程之外的另一个线程上执行时才为真,并且那里的 Invoke 在 UI 线程上执行 UpdateMe。基本上它说“if (notOnUiThread) { executeMeOnUIThread(); return; }”。这样您就可以从工作线程调用UpdateMe,而不必担心是否在 UI 线程上。
      【解决方案4】:

      这里是代码示例 [你想要什么] - http://www.yoda.arachsys.com/csharp/threads/winforms.shtml

      & 你可以在这里阅读所有的异步风格 -

      http://msdn.microsoft.com/en-us/library/2e08f6yc(v=vs.100).aspx

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2018-04-25
        • 2011-09-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多