【问题标题】:C# Control.Invoke a method groupC# Control.Invoke 方法组
【发布时间】:2013-04-05 13:17:56
【问题描述】:

我正在使用线程在程序的 UI 中运行长时间的操作,这样它就不会被锁定。但是,在这些任务中,我需要更新控件,这不可能不是来自创建它们的线程。建议使用 control.BeginInvoke(Delegate) 来执行你想要的方法。

但是,要做到这一点,您必须声明一个委托类型,然后才能调用它们。

所以,它是这样的:如果我想执行方法 void Update(),我必须去:

delegate void CallbackVoid();
void Update() {...}

...(in task code)...
this.BeginInvoke(new CallbackVoid(Update));

对于现有的每一种方法来说,这都是相当令人厌烦的。我不能以某种方式自然地做到这一点,例如:

void Update() {...}    
this.BeginInvoke(Update);

【问题讨论】:

    标签: c# multithreading delegates invoke


    【解决方案1】:

    简化事情的一个选项是添加扩展方法:

    public static void BeginInvokeAction(this Control control, Action action)
    {
        control.BeginInvoke(action);
    }
    

    然后你可以使用:

    this.BeginInvokeAction(action);
    

    这样做的原因是我们现在为编译器提供了一个具体的委托类型,以将方法组转换为。

    【讨论】:

      【解决方案2】:

      更新适用于 WPF!!!

      您可以在匿名方法中使用短语法,甚至无需声明您的方法

        Dispatcher.BeginInvoke(DispatcherPriority.Background, new MethodInvoker(() =>   
                      {
                         //Your Update code
                      }));
      

      【讨论】:

      • 这和 control.Invoke(new EventHandler(delegate {/* update control here */})) 有什么不同; ?哪个更好?
      • @Arie 两者都是正确的,但不是其他的。 MSDN 说:“delegate 可以是 EventHandler 的实例,在这种情况下,sender 参数将包含此控件,而 event 参数将包含 EventArgs.Empty。delegate 也可以是 MethodInvoker 的实例,或任何其他采用一个无效的参数列表。调用 EventHandler 或 MethodInvoker 委托将比调用另一种委托更快"
      • @voo:实际上这 对 Windows 窗体正确,这就是问题似乎是关于...
      • @JonSkeet 哦,你一如既往地是对的。我没有看到 winforms 标签,并且错过了“this”这个词:(我更新了我的答案
      【解决方案3】:

      尝试以下方法:

          if (this.controlname.InvokeRequired && !this.controlname.IsDisposed)
                      {
                          Invoke(new MethodInvoker(delegate()
                              {
                                  //Update control on GUI here!
      
          }));
          else if(!this.controlname.IsDisposed)
         {
                                 //AND here!
         }
      

      【讨论】:

      • 这实际上是更多代码,而不是更少,并且与任何其他解决方案相比没有任何优势。整个想法是 OP 知道他不在 UI 线程中;没有必要检查,他知道控件没有被释放(如果没有,老实说,崩溃会更好,这样你就可以找到/修复错误,而不是默默地继续)。
      【解决方案4】:

      BeginInvoke 是异步的,Invoke 是同步的,你使用哪一个取决于你想要做什么。如果您需要在继续之前完成调用,那么您需要同步调用。

      这是我最喜欢的同步调用构造:

       static void InvokeIfRequired(Control control, Action action)
       {
          if (control.InvokeRequired)
          {
              control.Invoke(action);
          }
          else
          {
              action.Invoke();
          }
       }
      

      使用:

      void MyTestFunction()
      {
          InvokeIfRequired(myControl, () =>
              {
                  MyFunction();
                  MyOtherFunction();
              });
      
          // Or more simply:
          InvokeIfRequired(myControl, () => MyFunction());
      }
      

      创建动作有一点开销,但它大大简化了代码,不必考虑各处的细节。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-04-29
        • 2015-10-07
        • 2023-04-08
        • 1970-01-01
        • 1970-01-01
        • 2013-02-26
        • 1970-01-01
        • 2015-09-30
        相关资源
        最近更新 更多