I am writing a little WPF application to test some SignalR code. Everything works from what I have written, but I have stumbled across something which I am unsure of.
I have created an event handler for the HubConnection
StateChanged
event;
_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");
}
};
With my Delegate method statusCallBack
and method being;
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();
}
}
Now I am probably missing something really obvious here, but when in the StateChanged
handler I check for ConnectionState.Connecting
and output the message to my Label it works fine.
Then when the SignalR HubConnection state then changes to ConnectionState.Connected
and I try to Invoke the delegate, the WPF app just locks up.
It will output to the console fine, and check to see if change.NewState == ConnectionState.Connected
, then will output "hello" to the console, but then just freezes.
If I debug the app, when it gets to within the Connected if
statement, the object change.NewState
and change.OldState
have the error message below.
I am lost as to why it works within the first if statement, but not the second. Also why it is able to output the correct values to the console?
Even if I comment out the initial if
statement to check for Connecting
it will still freeze when Connected
.
This is a common deadlock problem when calling back to the UI from an event.
Try using Dispatcher.BeginInvoke
rather than Invoke
.
As quoted in this thread:
When you use Dispatcher.BeginInvoke it means that it schedules the given action for execution in the UI thread at a later point in time, and then returns control to allow the current thread to continue executing. Invoke blocks the caller until the scheduled action finishes.
As a side-note: MVVM Light has a very useful helper called DispatcherHelper
that is not only compatible with virtually everything (WPF, WinRT, SL, etc.), but very simple to use. It helps you automatically dispatch calls back to the UI. If nothing else, it may be helpful to use the NUGet package JUST for this feature.