【问题标题】:Using the C# Dispatcher in WPF Applications在 WPF 应用程序中使用 C# 调度程序
【发布时间】:2011-10-20 16:45:00
【问题描述】:

我正在构建一个聊天客户端,但不能 100% 确定如何使用 dispatcher。所以问题是我有这样的方法:

public void LostConnection()
{
    myGUI.chatBox.AppendText("Lost connection to room: "+ myGUI.UsernameText.ToString() + "\r\n");
}

我是否需要用Dispatcher.Invoke 来替代(myGUI.chatBox... ) 中的语句?感谢您的帮助。

【问题讨论】:

  • 这取决于... 该方法在哪个线程上运行?另外,为了确定,您使用的是 WPF,对吧? (Dispatcher 仅适用于此。)
  • 您使用的是什么 UI 框架? (WinForms、WPF 或 SL)它们之间存在差异
  • 是的,就像 svick 建议的那样,这取决于您是否从另一个线程(异步)触摸您的 UI
  • 我很抱歉没有指定它是一个 wpf 应用程序并且它是我的后端试图更新我的 GUI,所以是的,它是跨线程的。我想我已经成功了,所以感谢所有提供帮助的人!!!

标签: c# wpf invoke dispatcher


【解决方案1】:

您的应用有一个主 UI 线程(通常是 ManagedThreadId==1)。通常在聊天应用程序中,您的事件将进入其他线程(专用套接字侦听线程或来自侦听代码的线程池线程)。如果你想从一个在其他线程上拉取的事件更新 UI,你必须使用调度程序。这里一个有用的测试是 Dispatcher.CheckAccess() 方法,如果代码在 UI 线程上,则返回 true,如果在其他线程上,则返回 false。典型的调用如下所示:

using System.Windows.Threading; // For Dispatcher.

if (Application.Current.Dispatcher.CheckAccess()) {
    network_links.Add(new NetworkLinkVM(link, start_node, end_node));
}
else {
    Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(()=>{
        network_links.Add(new NetworkLinkVM(link, start_node, end_node));
    }));
}

如果您在主窗口中,您可以使用:

Dispatcher.BeginInvoke(...

如果您处于其他上下文中,例如视图模型,请使用:

Application.Current.Dispatcher.BeginInvoke(  

Invoke 与 BeginInvoke
如果您希望当前线程等待 UI 线程处理完调度代码,请使用 Invoke;如果您希望当前线程继续运行而不等待 UI 线程上的操作完成,请使用 BeginInvoke

MessageBox、Dispatchers 和 Invoke/BeginInvoke:
Dispatcher.Invoke 将阻止您的线程,直到 MessageBox 被解除。
Dispatcher.BeginInvoke 将允许您的线程代码继续执行,同时UI 线程将阻塞 MessageBox 调用,直到它被解除。

CurrentDispatcher 与 Current.Dispatcher!
请注意Dispatcher.CurrentDispatcher,因为我对此的理解是,它将为当前线程而不是 UI 线程返回一个 Dispatcher。通常你对 UI 线程上的调度程序感兴趣 - Application.Current.Dispatcher 总是返回这个。

补充说明:
如果您发现必须经常检查调度程序 CheckAccess,那么一个有用的帮助方法是:

public void DispatchIfNecessary(Action action) {
    if (!Dispatcher.CheckAccess())
        Dispatcher.Invoke(action);
    else
        action.Invoke();
}

可以这样称呼:

DispatchIfNecessary(() => {
    network_links.Add(new NetworkLinkVM(link, start_node, end_node));
});

【讨论】:

  • 大家好,对不起,我没有具体说明,是的,它是一个 wpf 应用程序,是的,它是跨线程的。我在后端设置委托,然后提醒我的模型,然后调用该调度程序方法并更新 gui 接口。我仍然没有使用 intellesense 添加调度程序的选项,但我会尝试强制它并查看它是否运行。多谢你们!还有其他提示吗?
  • 如果你已经包含 using 语句并使用 Application.Current.Dispatcher 你应该得到一个结果。如果您的“后端”在 dll 中,那么您需要将 UI 线程 Dispatcher 传递到您的对象中,以便它可以引用它。
  • @Ricibob,只是为了挑剔,我认为 UI 线程并不总是必须具有 1 的 ID。
  • 加一票,因为您编写了 using 指令,这对 C# 初学者有很大帮助。
【解决方案2】:

Application.Current.Dispatcher.BeginInvokeobject.Invoke() 方法有问题。

这对我有用:

Dispatcher.CurrentDispatcher.BeginInvoke(new Action(() =>
{
     // code...
}));

【讨论】:

【解决方案3】:

这样的事情(在我的脑海中)应该可以工作:

public void LostConnection() 
{ 
   myGUI.Invoke
      ((MethodInvoker)delegate
   {
      myGUI.chatBox.AppendText("Lost connection to room: "+ myGUI.UsernameText.ToString() + "\r\n"); 
   });
}

【讨论】:

  • 那将在 WinForms 中。这个问题显然是关于 WPF 的。
  • 是的。这在问题中并不明显。
猜你喜欢
  • 2014-08-23
  • 1970-01-01
  • 1970-01-01
  • 2012-05-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多