首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >清理散落着InvokeRequired的代码

清理散落着InvokeRequired的代码
EN

Stack Overflow用户
提问于 2010-10-06 23:26:24
回答 7查看 17.5K关注 0票数 48

我知道当从任何非UI线程操作UI控件时,您必须将调用编组到UI线程以避免出现问题。一般的共识是您应该使用测试InvokeRequired,如果是真的,那么使用.Invoke来执行封送处理。

这导致了大量的代码,如下所示:

代码语言:javascript
运行
复制
private void UpdateSummary(string text)
{
    if (this.InvokeRequired)
    {
        this.Invoke(new Action(() => UpdateSummary(text)));
    }
    else
    {
        summary.Text = text;
    }
}

我的问题是:我是否可以省略InvokeRequired测试,只调用Invoke,如下所示:

代码语言:javascript
运行
复制
private void UpdateSummary(string text)
{
    this.Invoke(new Action(() => summary.Text = text));
}

这样做有问题吗?如果是这样的话,有没有一种更好的方法来保留InvokeRequired测试,而不必到处复制和粘贴这个模式?

EN

回答 7

Stack Overflow用户

回答已采纳

发布于 2010-10-06 23:29:52

好吧,这样如何:

代码语言:javascript
运行
复制
public static class ControlHelpers
{
    public static void InvokeIfRequired<T>(this T control, Action<T> action) where T : ISynchronizeInvoke
    {
        if (control.InvokeRequired)
        {
            control.Invoke(new Action(() => action(control)), null);
        }
        else
        {
            action(control);
        }
    }
}

像这样使用它:

代码语言:javascript
运行
复制
private void UpdateSummary(string text)
{
    summary.InvokeIfRequired(s => { s.Text = text });
}
票数 66
EN

Stack Overflow用户

发布于 2010-10-06 23:29:46

从UI线程调用Invoke的效率有点低。

相反,您可以创建一个接受Action参数的InvokeIfNeeded扩展方法。(这也允许您从调用站点中删除new Action(...) )

票数 8
EN

Stack Overflow用户

发布于 2010-10-07 02:32:55

我一直在阅读关于添加逻辑检查的来回参数,以确定当不在UI线程和UI线程本身上时是否应该使用invoke。我写了一个类,检查执行(通过秒表)各种方法的时间,以获得一个方法相对于另一个方法的效率的粗略估计。

结果可能会让你们中的一些人感到惊讶(这些测试是通过Form.Shown事件运行的):

代码语言:javascript
运行
复制
     // notice that we are updating the form's title bar 10,000 times
     // directly on the UI thread
     TimedAction.Go
     (
        "Direct on UI Thread",
        () =>
        {
           for (int i = 0; i < 10000; i++)
           {
              this.Text = "1234567890";
           }
        }
     );

     // notice that we are invoking the update of the title bar
     // (UI thread -> [invoke] -> UI thread)
     TimedAction.Go
     (
        "Invoke on UI Thread",
        () =>
        {
           this.Invoke
           (
              new Action
              (
                 () =>
                 {
                    for (int i = 0; i < 10000; i++)
                    {
                       this.Text = "1234567890";
                    }
                 }
              )
           );
        }
     );

     // the following is invoking each UPDATE on the UI thread from the UI thread
     // (10,000 invokes)
     TimedAction.Go
     (
        "Separate Invoke on UI Thread",
        () =>
        {
           for (int i = 0; i < 10000; i++)
           {
              this.Invoke
              (
                 new Action
                 (
                    () =>
                    {
                       this.Text = "1234567890";
                    }
                 )
              );
           }
        }
     );

结果如下:

调试:在UI线程上直接调试秒表:300ms

  • TimedAction::Go()+0 -调试:在UI线程上调试秒表调用:299ms

  • TimedAction::Go()+0 -调试:调试秒表在UI线程上单独调用:649ms

我的结论是,无论您是在UI线程上还是在工作线程上,您都可以在任何时候安全地调用,而不会产生通过消息泵循环返回的大量开销。但是,在UI线程上执行大部分工作,而不是对UI线程进行大量调用(通过Invoke())是有利的,并且可以极大地提高效率。

票数 7
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/3874134

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档