使用Dispatcher.Invoke从非主线程更改WPF控件

D. *_*per 69 c# wpf multithreading dispatcher

我最近开始在WPF编程并遇到了以下问题.我不明白如何使用该Dispatcher.Invoke()方法.我有线程经验,我做了一些简单的Windows窗体程序,我只是使用了它

Control.CheckForIllegalCrossThreadCalls = false;
Run Code Online (Sandbox Code Playgroud)

是的我知道这很蹩脚,但这些都是简单的监控应用程序.

事实是,现在我想提出一个WPF应用程序在后台检索数据,我开始了一个新的线程进行调用来检索(从网络服务器)的数据,现在我要显示它在我的WPF形式.问题是,我不能从这个线程设置任何控制.甚至没有标签或任何东西.怎么解决这个问题?

回答评论:
@Jalfp:
所以当我得到数据时,我在'new tread'中使用这个Dispatcher方法?或者我应该让后台工作程序检索数据,将其放入一个字段并启动一个等待该字段填满的新线程并调用调度程序将检索到的数据显示到控件中?

jap*_*apf 167

首先要理解的是,Dispatcher不是为运行长阻塞操作而设计的(例如从WebServer检索数据......).如果要运行将在UI线程上执行的操作(例如更新进度条的值),可以使用Dispatcher.

您可以做的是在后台工作程序中检索数据并使用ReportProgress方法在UI线程中传播更改.

如果你真的需要直接使用Dispatcher,那很简单:

Application.Current.Dispatcher.BeginInvoke(
  DispatcherPriority.Background,
  new Action(() => this.progressBar.Value = 50));
Run Code Online (Sandbox Code Playgroud)

  • 你可以摆脱'new Action('部分,只需使用lambda表达式:DispatcherPriority.Background,()=> this.progressBar.Value = 50 (21认同)
  • @jrista:你真的吗?我在没有`new Action(...)`的情况下尝试[CS1660](http://msdn.microsoft.com/en-us/library/hy74she2%28v=vs.80%29.aspx). (10认同)
  • @jrista:总的来说,虽然[这篇文章](http://visualstudiomagazine.com/articles/2009/02/01/use-lambda-expressions-for-abstract-delegates.aspx)解释了为什么它没有在无参数方法的情况下工作,例如传递给`BeginInvoke`的方法,而不是编译器错误CS1660. (6认同)
  • @Carsten 这个答案适用于使用 System.Windows.Application 类的 WPF 应用程序。 (3认同)
  • 是的,不知道为什么我在这里放一个 Action :p (2认同)

Yog*_*gee 25

japf已正确回答.如果您正在查看多行操作,可以按如下方式编写.

Application.Current.Dispatcher.BeginInvoke(
  DispatcherPriority.Background,
  new Action(() => { 
    this.progressBar.Value = 50;
  }));
Run Code Online (Sandbox Code Playgroud)

想要了解性能的其他用户的信息:

如果您的代码需要为高性能编写,您可以首先使用CheckAccess标志检查是否需要调用.

if(Application.Current.Dispatcher.CheckAccess())
{
    this.progressBar.Value = 50;
}
else
{
    Application.Current.Dispatcher.BeginInvoke(
      DispatcherPriority.Background,
      new Action(() => { 
        this.progressBar.Value = 50;
      }));
}
Run Code Online (Sandbox Code Playgroud)

请注意,方法CheckAccess()在Visual Studio 2015中是隐藏的,因此只需编写它而不需要智能感知来显示它.请注意,CheckAccess的性能开销(开销只有几纳秒).只有当您想要不惜任何代价保存执行"调用"所需的微秒时,才会更好.此外,当调用方法确定它是否在UI线程中时,总是有选项可以创建两个方法(on with invoke,and other without).当您应该关注调度员的这个方面时,这是罕见的罕见情况.


小智 7

当一个线程正在执行并且您想要执行被当前线程阻塞的主 UI 线程时,请使用以下命令:

当前线程:

Dispatcher.CurrentDispatcher.Invoke(MethodName,
    new object[] { parameter1, parameter2 }); // if passing 2 parameters to method.
Run Code Online (Sandbox Code Playgroud)

主用户界面线程:

Application.Current.Dispatcher.BeginInvoke(
    DispatcherPriority.Background, new Action(() => MethodName(parameter)));
Run Code Online (Sandbox Code Playgroud)