我正在编写一个小的WPF应用程序来测试一些SignalR代码。一切都与我所写的一致,但我偶然发现了一些我不确定的东西。
我为HubConnection
StateChanged
事件创建了一个事件处理程序;
_hub.StateChanged += (change) =>
{
Console.WriteLine("hubConnection.StateChanged {0} => {1}", change.OldState, change.NewState);
if (change.NewState == ConnectionState.Connecting)
{
statusCallBack callBack = new statusCallBack(UpdateStatus);
this.Dispatcher.Invoke(callBack, "hubConnection.StateChanged");
}
if (change.NewState == ConnectionState.Connected)
{
Console.WriteLine("hello");
statusCallBack callBack = new statusCallBack(UpdateStatus);
this.Dispatcher.Invoke(callBack, "hubConnection.StateChanged");
}
};
使用我的Delegate方法statusCallBack
和方法;
delegate void statusCallBack(string msg);
private void UpdateStatus(string msg)
{
if (this.Dispatcher.CheckAccess() == true)
{
this.tbStatus.AppendText(Environment.NewLine + DateTime.Now.ToLongTimeString() + " --- " + msg);
this.tbStatus.CaretIndex = this.tbStatus.Text.Length;
this.tbStatus.ScrollToEnd();
}
}
现在我可能遗漏了一些非常明显的东西,但是当我在StateChanged
处理程序中检查ConnectionState.Connecting
并将消息输出到我的Label时,它工作正常。
然后当SignalR HubConnection状态变为ConnectionState.Connected
并尝试调用委托时,WPF应用程序就会锁定。
它会很好地输出到控制台,并检查是否change.NewState == ConnectionState.Connected
,然后将“hello”输出到控制台,然后冻结。
如果我调试应用,当它进入Connected if
语句时,对象change.NewState
和change.OldState
会出现以下错误消息。
我迷失了为什么它在第一个if语句中起作用,但不是第二个。为什么它能够将正确的值输出到控制台?
即使我发表评论if
的初始Connecting
语句,它仍会在Connected
时冻结。
答案 0 :(得分:2)
从事件回调UI时,这是一个常见的死锁问题。
尝试使用Dispatcher.BeginInvoke
而不是Invoke
。
引用this帖子:
当您使用Dispatcher.BeginInvoke时,它意味着它会安排 给定在稍后的UI线程中执行的操作, 然后返回控件以允许当前线程继续 执行。调用会阻止调用者直到计划的操作 饰面。
作为旁注:MVVM Light有一个非常有用的帮助程序DispatcherHelper
,它不仅与几乎所有东西(WPF,WinRT,SL等)兼容,而且使用起来非常简单。它可以帮助您自动将呼叫分配回UI。如果不出意外,使用NUGet软件包JUST可能会对此功能有所帮助。