使用DispatcherObject的VerifyAccess和CheckAccess方法

时间:2010-09-06 09:06:12

标签: c# wpf silverlight custom-controls dispatcher

在浏览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 个答案:

答案 0 :(得分:6)

不,从未使用过这个。并且从未注意到有人在自定义控件的上下文中使用它。 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()时,您会阻止调用线程,直到UI线程处理您的请求为止。这导致性能不佳。当然,您可以将此更改为Dispatcher.BeginInvoke(),现在您的客户应该知道他们的操作是异步完成的。即如果客户端写入要控制的内容,然后立即将其读回,则无法保证该操作已由UI线程执行。

问题2。考虑从非UI线程调用方法Foo()。例如,它在循环中调用:

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

开发人员可以在调用线程中实现一次检查,并在必要时转移到UI,而不是在线程之间无意识地跳回去,而不是阻塞调用线程1000000次。

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

希望这有帮助。