2013-08-16 48 views
0

我在寫一個WPF應用程序來測試一些SignalR代碼。一切都從我所寫的內容開始,但我偶然發現了一些我不確定的東西。SignalR WPF StateChange問​​題

我爲HubConnectionStateChanged事件創建了一個事件處理程序;

_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"); 
    } 
}; 

用我的委託方法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和輸出信息到我的標籤,它工作正常。

然後,當SignalR HubConnection狀態然後更改爲ConnectionState.Connected,我嘗試調用該委託時,WPF應用程序就鎖定了。

它將輸出到控制檯罰款,並檢查,看看是否change.NewState == ConnectionState.Connected,然後將輸出「你好」的控制檯,但後來只是凍結。

如果我調試應用程序,當它進入連接的if語句內時,對象change.NewStatechange.OldState在下面有錯誤消息。

enter image description here

View larger image here.

我迷路了,爲什麼它的工作原理中的第一個if語句,而不是第二。另外爲什麼它能夠輸出正確的值到控制檯?

即使我註釋掉最初的if聲明來檢查Connecting它仍然會凍結時Connected

回答

2

從事件回調到UI時,這是一個常見的死鎖問題。使用Dispatcher.BeginInvoke而不是Invoke

正如this螺紋報價:

當您使用Dispatcher.BeginInvoke這意味着它的時間表定在時間, 稍後在UI線程執行操作,然後將控制返回給 允許當前線程繼續執行 。調用阻止調用者,直到預定的動作 完成。

作爲一個側面說明:MVVM光有所謂DispatcherHelper一個非常有用的幫手,不僅幾乎一切(WPF,WinRT中,SL等)兼容,但使用起來非常簡單。它可以幫助您自動將呼叫分派回UI。如果沒有其他內容,對此功能使用NUGet包JUST可能會有所幫助。

+0

非常感謝。我現在可以繼續我的生活:P我會檢查出MVVM Light。 –

+0

是的!當你得到錯誤時肯定有什麼錯誤'這種類型的CollectionView不支持從與分派器線程不同的線程對其SourceCollection的更改。' '儘管'System.Threading.Thread.CurrentThread == System.Windows.Threading.Dispatcher.CurrentDispatcher.Thread'爲true –