使用DispatcherObject的VerifyAccess和CheckAccess方法

akj*_*shi 4 c# silverlight wpf custom-controls dispatcher

同时,通过去这个文章中,我碰到这个声明是-

如果您正在编写自己的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
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

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

  • 你在构建自定义控件时使用它吗?
  • 是这样做还是只是很高兴?
  • 有人因为你的控件中没有这个问题而面临任何问题吗?

Anv*_*aka 7

不,从来没用过这个.并且从未注意到有人在自定义控件的上下文中使用它.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.
}
Run Code Online (Sandbox Code Playgroud)

乍一看这段代码看起来很好.如果您不在UI线程中,则转移到UI线程,执行操作并返回结果.对? - 错了!

问题1.当你打电话给Dispatcher.Invoke()你时,阻止调用线程直到你的请求被UI线程处理.这导致性能不佳.当然,您可以将此更改为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!
}
Run Code Online (Sandbox Code Playgroud)

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

此外,当您从非UI线程访问UI元素时,WPF将为您进行此检查.它的声音很大,足以粉碎应用程序,并且被做错了的开发人员听到了:).

希望这可以帮助.