【问题标题】:Illegal Cross Thread Call when updating control更新控件时非法跨线程调用
【发布时间】:2015-11-15 16:06:51
【问题描述】:

我在WinForms 中搜索了很多异步更新 UI 控件的示例,并且大多数示例都有大量代码。有没有办法让这更容易?我只是觉得他们现在工作太多了。

我见过人们这样做:

await Task.Run(() =>
{
    doSomething();
});

但我听说这很糟糕而且不能正常工作,而且我不喜欢在我的 UI 代码中添加多个 await Task.Run(()=> {}); 实例。而且我已经看到了大量关于后台工作人员的示例。

有没有不需要太多样板代码的更好方法?

【问题讨论】:

  • 一个更好的方法来做什么?您发布的代码 sn-p 本身并没有什么问题,但是上下文太少,以至于实际上没有什么有用的东西可以说。 Task.Run() 是今天恕我直言,处理长时间运行的操作的最佳方式,否则,await 是将 UI 代码与此类长时间运行的操作同步的最佳方式。
  • 但是您的问题中没有任何内容可以提供任何真正的问题陈述。事实是,正确地完成不会使用工作任务和更新 UI 的大量额外代码;如果你有很多额外的代码,你做错了。但是没有办法帮助你知道如何修复你做错的代码,除非你提供a good, minimal, complete code example,清楚地表明你在说什么。
  • 我只想在不调用非法跨线程错误的情况下更新代码
  • 您的问题中没有任何内容实际上要求这样做。如果这实际上就是您想知道的全部内容,那么 Stack Overflow 上已经有很多问题和答案可以解决这个问题。您所要做的就是搜索异常消息文本。
  • 如果建议的答案确实回答了您打算提出的问题,那么您的问题就是重复的。已经有几个答案与此处发布的相同,包括这个(实际上优于此处发布的):stackoverflow.com/a/3874177

标签: c# winforms


【解决方案1】:

我喜欢使用一种方法:

  1. 创建一个调用操作的控件扩展:

    public static void Update(this Control ctrl, Action a)
    {
        if (ctrl.InvokeRequired) 
        { 
            ctrl.BeginInvoke(new MethodInvoker(a), null); 
        }
        else 
        { 
            a.Invoke(); 
        }
    }
    
  2. 然后这样称呼它:control.Update(()=> { /* code to update control */ });

例如:

listView1.Update(() =>
{
    ListViewItem lvi = new ListViewItem("something");
    lvi.SubItems.Add("something else");
    listView1.Items.Add(lvi);
});

【讨论】:

  • (1) 这只不过是Control.Invoke 的缩减版(因此是有限的)。 (2) 包含冗余 - 'new MethodInvoker(a)' 而不仅仅是 a。 (3) 做不同的事情(BeginInvoke vs Invoke
  • @IvanStoev 谢谢!我很感激反馈。刚刚注意到冗余。出于好奇,这是如何限制的?为什么要使用 BeginInvoke 与 Invoke?
  • Control.Invoke是同步的(阻塞调用非UI线程,直到调用被UI线程处理),而BeginInvoke类似,但不阻塞调用线程。两者都有用途。你的方法是有限制的,嗯,因为它没有提供那种灵活性。并且由于您强制使用委托,因此上面的代码相当于 listView1.BeginInvoke(new Action(() => ....)) 只是为了使用具体的 Delegate(在这种情况下为 Action)。请注意,将代码放入委托后,无需检查InvokeRequired
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-07-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多