beginInvoke, GUI and thread

6

我有一个应用程序,其中包含两个线程。其中一个(T1)是主GUI窗体,另一个(T2)是在循环中工作的功能。当T2获取一些信息后,必须调用带有GUI表单的函数。

我不确定我是否做得正确。

T2调用函数FUNCTION,该函数更新GUI表单中的某些内容。

  public void f() {
        // controler.doSomething();
  }


 public void FUNCTION() {

    MethodInvoker method = delegate {
            f();
    };

    if ( InvokeRequired ) {
        BeginInvoke( method );
    } else {
            f();
    }
 }

但现在我必须声明两个函数。如何只使用一个函数?或者说,它是否正确。

2个回答

16

您可以通过调用自身来在单个方法中完成此操作:

public void Function()
{
     if (this.InvokeRequired)
     {
         this.BeginInvoke(new Action(this.Function));
         return;
     }

     // controller.DoSomething();         
}

根据评论的反馈进行编辑:

如果需要传递额外参数,可以使用lambda表达式来实现,如下所示:

public void Function2(int someValue)
{
     if (this.InvokeRequired)
     {
         this.BeginInvoke(new Action(() => this.Function2(someValue)));
         return;
     }

     // controller.DoSomething(someValue);         
}

1
不错的模式。如果您从第二个线程调用,则需要一个递归调用来调用自己。我认为应该同步进行调用,这样来自第二个线程的调用(看起来是同步的;只是普通的方法调用)将以与从GUI线程调用相同的方式工作,在返回之前执行适当的任务。 - KeithS
有趣:我从没见过这样做...它不会导致无限循环吗??? - IAbstract
1
@nirmus - 在这种情况下,您需要将不带参数且返回void的非泛型Action更改为泛型Func<int, string>(它将接受一个int参数并返回一个string参数)。请注意,您可以插入到MethodInvoker委托中的内容是有限制的;您可能需要“柯里化”您的调用以减少或消除参数。 - KeithS
@IAbstract - 正确。当从第二个线程调用函数时,InvokeRequired为真,并且该函数在GUI线程上安排了一个调用到自身。当进行该调用并且Function第二次执行时,InvokeRequired为false,因为该函数现在在GUI线程中执行。 - KeithS
感谢Reed和@Keith提供的信息。我刚刚完成了一个与你第二个示例完全相同的代码片段...哈哈,我喜欢Stack Overflow... - IAbstract
显示剩余6条评论

3

我认为这看起来很不错。您可以将匿名委托更改为lambda表达式,这样会更加简洁。要消除f()方法声明,请将其代码内联到委托中,然后将委托作为MethodInvoker调用或像调用其他任何方法一样直接调用它:

 public void FUNCTION() {

    MethodInvoker method = ()=> controller.doSomething();

    if ( InvokeRequired ) {
        BeginInvoke( method );
    } else {
            method();
    }
 }

这是一个不错的解决方案。我必须学习一些关于lambda函数的知识,因为我发现它有很多有趣的可能性。感谢您的帮助。 - nirmus

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接