【问题标题】:InvokeRequired in wpf [duplicate]wpf中的InvokeRequired [重复]
【发布时间】:2013-03-08 10:37:00
【问题描述】:

我在一个Windows forms 应用程序中使用了这个函数:

delegate void ParametrizedMethodInvoker5(int arg);

private void log_left_accs(int arg)
{
    if (InvokeRequired) 
    {
        Invoke(new ParametrizedMethodInvoker5(log_left_accs), arg);
        return;
    }

    label2.Text = arg.ToString();
}

但在WPF 中它不起作用。为什么?

【问题讨论】:

    标签: c# wpf winforms invokerequired


    【解决方案1】:

    在 WPF 中,Invoke 方法在调度程序上,因此您需要调用 Dispatcher.Invoke 而不是 Invoke。此外,没有InvokeRequired 属性,但调度程序有一个CheckAccess 方法(出于某种原因,它隐藏在智能感知中)。所以你的代码应该是:

    delegate void ParametrizedMethodInvoker5(int arg);
    void log_left_accs(int arg)
    {
        if (!Dispatcher.CheckAccess()) // CheckAccess returns true if you're on the dispatcher thread
        {
            Dispatcher.Invoke(new ParametrizedMethodInvoker5(log_left_accs), arg);
            return;
        }
        label2.Text= arg.ToString();
    }
    

    【讨论】:

    • Dispatcher 的值可能是null。这就是为什么DispatcherObjectCheckAccess 方法的原因,它解释了这种可能性
    • @JaredPar,你知道在哪种情况下 Dispatcher 可以为空吗?我以前从未见过它...
    • 我相信当一个对象被冻结时,它的Dispatcher 将是null。寻找对DispatherObject.DetachFromDispatcher的引用
    • 这个“隐藏在智能感知中”让我有点恼火。不应该相信它...
    • 很好的答案,但没有委托它更容易? Dispatcher.Invoke(new Action(() => log_left_accs(arg)));
    【解决方案2】:

    在 WPF 中使用 CheckAccess 方法而不是 InvokeRequired

    if (!CheckAccess()) { 
      // On a different thread
      Dispatcher.Invoke(() => log_left_accs(arg));
      return;
    }
    

    【讨论】:

    • CheckAccess 是调度程序的方法,而不是窗口或控件的方法
    • @ThomasLevesque 它也是 DispatcherObject 上的一个方法,它是大多数 WPF 控件值的根
    • @JaredPar,确实如此。由于 Invoke 不能在 DispatcherObject 上直接访问,我假设它与 CheckAccess 相同。
    【解决方案3】:

    【讨论】:

      【解决方案4】:

      WPF 使用Dispatcher 来控制对消息泵的访问,而不是让每个控件负责访问 UI 线程。

      您应该使用Dispatcher.Invoke 将委托添加到 WPF 应用程序中的 UI 线程。

      还值得注意的是,InvokeRequired 在 winform 应用程序中并不是真正需要的,也不是您应该在 WPF 应用程序中检查的东西。当您调用Invoke 时,您应该知道您不在 UI 线程中。您不应该处于有时从 UI 线程调用给定方法,有时从后台线程调用给定方法的情况。选一个;要么总是强制调用者在调用给定方法之前调用 UI 线程(所以你不需要调用),或者假设调用者在调用方法时不会在 UI 线程中。还值得注意的是,当您已经在 UI 线程中时调用 Invoke 就可以了。偶尔重新调用 UI 线程不会导致错误或问题(性能成本非常低,所以不要到处添加不需要的代码)。

      【讨论】:

      • 当然有很多情况你不知道自己是否在创建线程中,必须检查它!
      • 曾经做过允许数据绑定的用户控件吗?数据通常由另一个线程获取,但写入例如设置文本框的值也可以由另一个控件完成(例如,更改下拉菜单会导致另一个默认值 => 您在 UI 线程上。从数据库分配值 => 您在工作线程上)
      • 顺便说一句,不要使用 Invoke(),而是使用 BeginInvoke()(在 WinForms 和 WPF 中)。原因是 Invoke() 可能会导致丑陋的死锁。
      • @chha 是的,有可能将自己置于不知道自己是否在 UI 线程中的情况。然而,在绝大多数情况下,应该避免这种情况。应该有一些 UI 操作假定它们只从 UI 线程调用,以及知道它们不是从 UI 线程调用的方法。当从已知的非 UI 相关方法调用 UI 相关方法时,就是您调用的时候。应避免将自己置于具有打算从 UI 和非 UI 操作调用的方法的境地。是的,确实存在一些例外情况。
      • @chha 在某些情况下同步调用很重要,而在某些情况下异步调用很重要。两者都有自己的位置,并且在不适当的情况下使用时都有潜在的问题。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-09-07
      • 1970-01-01
      • 1970-01-01
      • 2013-04-24
      相关资源
      最近更新 更多