代码之家  ›  专栏  ›  技术社区  ›  akjoshi HCP

使用DispatcherObject的VerifyAccess和CheckAccess方法

  •  3
  • akjoshi HCP  · 技术社区  · 15 年前

    在经历 this 我看到这个声明的文章-

    如果你正在写你自己的WPF 对象,如控件,所有方法 使用时应调用VerifyAccess 在他们进行任何工作之前。这个 确保您的对象仅 在UI线程上使用,如下所示

    //Using VerifyAccess and CheckAccess 
    public class MyWpfObject : DispatcherObject
    {
        public void DoSomething()       
        {
            VerifyAccess();
    
            // Do some work
        }
    
        public void DoSomethingElse()
        {
            if (CheckAccess())
            {
                // Something, only if called 
                // on the right thread
            }
        }
    }
    

    在我遇到的任何自定义控件中(据我记忆中),我都没有看到过这种情况。

    • 在构建自定义控件时是否使用此选项?
    • 是必须这样做还是只是很高兴拥有?
    • 有没有人因为你的控制中没有这个问题而面临过任何问题?
    1 回复  |  直到 14 年前
        1
  •  6
  •   Anvaka    15 年前

    不,从来没用过这个。从未注意到有人在自定义控件的上下文中使用它。WPF工具箱中也不遵循此规则。

    这种方法不仅污染代码,而且使您的自定义控件对它不应该关心的事情负责。考虑一下你一直在做的事情:

    // Don't do this in all methods of your custom control!
    public void Foo()
    {
      if (!CheckAccess())
      {
        Dispatcher.Invoke(()=> Foo()); // Transit to UI Thread
        return;
      }
      // .. do work in UI.
    }
    

    乍一看,这个代码看起来不错。如果您不在UI线程中,则转到UI线程,执行操作并返回结果。正确的?-错了!

    问题1。 当你打电话 Dispatcher.Invoke() 在用户界面线程处理请求之前,您会阻止调用线程。这会导致性能不佳。当然,你可以把这个改成 Dispatcher.BeginInvoke() 现在,您的客户机应该知道他们的操作是异步完成的。也就是说,如果客户机将某个内容写入控件,然后立即将其读回来,则无法保证该操作已经由UI线程执行。

    问题2。 考虑对该方法的后续调用 Foo() 来自非UI线程。例如,它在循环中调用:

    // Somewhere not in UI
    for (int i = 0; i < 1000000; i++)
    {
      control.Foo(); // Looks good, but performance is awful!
    }
    

    开发人员可以在调用线程中实现一次签入,并在必要时传输到UI,而不是在线程之间无意识地返回值,而不是阻止调用线程1000000次。

    此外,当您从非UI线程访问UI元素时,WPF将为您进行此检查。它的尖叫声足以压碎应用程序,并被出错的开发人员听到:)。

    希望这有帮助。