Проблемы SignalR WPF с изменением состояния

Я пишу небольшое приложение 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 и вывожу сообщение в свою метку, все работает нормально.

Затем, когда состояние SignalR HubConnection затем изменяется на ConnectionState.Connected, и я пытаюсь вызвать делегата, приложение WPF просто блокируется.

Он выведет на консоль нормально и проверит, есть ли change.NewState == ConnectionState.Connected, затем выведет «привет» на консоль, но потом просто зависнет.

Если я отлаживаю приложение, когда оно попадает в оператор Connected if, объекты change.NewState и change.OldState имеют сообщение об ошибке ниже.

введите здесь описание изображения

Просмотреть увеличенное изображение здесь.

Я не понимаю, почему это работает в первом операторе if, но не во втором. Также почему он может выводить правильные значения в консоль?

Даже если я закомментирую начальный оператор if для проверки Connecting, он все равно зависнет, когда Connected.


person Tim B James    schedule 16.08.2013    source источник


Ответы (1)


Это распространенная проблема взаимоблокировки при обратном вызове пользовательского интерфейса из события.

Попробуйте использовать Dispatcher.BeginInvoke вместо Invoke.

Как указано в этой теме:

Когда вы используете Dispatcher.BeginInvoke, это означает, что он планирует данное действие для выполнения в потоке пользовательского интерфейса в более поздний момент времени, а затем возвращает управление, чтобы позволить текущему потоку продолжить выполнение. Invoke блокирует вызывающего абонента до завершения запланированного действия.

В качестве примечания: у MVVM Light есть очень полезный помощник под названием DispatcherHelper, который не только совместим практически со всем (WPF, WinRT, SL и т. д.), но и очень прост в использовании. Это помогает автоматически отправлять звонки обратно в пользовательский интерфейс. Если ничего другого, может быть полезно использовать пакет NUGet ТОЛЬКО для этой функции.

person Killnine    schedule 05.08.2014
comment
Большое спасибо за это. Теперь я могу жить дальше :P Я проверю MVVM Light. - person Tim B James; 05.08.2014
comment
да! определенно что-то не так, когда вы получаете сообщение об ошибке This type of CollectionView does not support changes to its SourceCollection from a thread different from the Dispatcher thread.' несмотря на то, что System.Threading.Thread.CurrentThread == System.Windows.Threading.Dispatcher.CurrentDispatcher.Thread верно - person Simon_Weaver; 10.02.2017