c # wpf dispatcher.beginInvoke freeze

1

im работает над приложением, которое общается с сервером.

thread  = new Thread(new ThreadStart(ClientStart));
thread.SetApartmentState(ApartmentState.STA);                
thread.Start();

private void ClientStart()
    {
        tcpClient = new TcpClient(ip,3000);
        stream = tcpClient.GetStream();
        while (true) {                
            stream.Read(...);
            PrintMessage(...);
        .....
        }
}
private void PrintMessage(LogWin w, string msg)
{
  DateTime dt = DateTime.Now;
  w.GetMessageBox().Dispatcher.BeginInvoke(DispatcherPriority.Input,new Action(()=>w.GetMessageBox()
            .AppendText(String.Format("{0:d/M/yyyy HH:mm:ss}", dt) + " : " + msg)));

}

позже мне нужно напечатать результат в окне сообщений. Я знаю, что мне нужно использовать Dispatcher, потому что im работает в другом потоке, но мое приложение зависает, даже если я использую метод beginInvoke.

Редактировать на основе ответа Шеридан:

теперь im получение: необработанное исключение типа "Исключение System.InvalidOperationException" произошло в WindowsBase.dll

Дополнительная информация: вызывающий поток не может получить доступ к этому объекту, потому что ему принадлежит другой поток.

Dispatcher dispatcher = Dispatcher.CurrentDispatcher;
thread = new Thread(() => ClientStart(dispatcher));
thread.SetApartmentState(ApartmentState.STA);
thread.Start();

private void ClientStart(Dispatcher dispatcher)
    { 
....

и изменил метод печати:

 dispatcher.BeginInvoke(DispatcherPriority.Input, new Action(() =>
       w.GetMessageBox()
            .AppendText(String.Format("{0:d/M/yyyy HH:mm:ss}", dt) + " : " + msg)));

решаются с помощью Application.Current.Dispatcher

Теги:
wpf
dispatcher
freeze

2 ответа

4
Лучший ответ

Всегда будьте осторожны с Dispatcher.CurrentDispatcher как это вернет объект для отправки в поток CURRENT, что может и не быть пользовательским интерфейсом. Вы хотите (и обычно почти всегда хотите) диспетчер потоков пользовательского интерфейса.

Вы можете получить это через Application.Current.Dispatcher который всегда возвращает диспетчер потоков пользовательского интерфейса.

Его отвращение, что эти вызовы выглядят так похожими...

[Если вы находитесь в главном окне, вы можете просто вызвать Dispatcher но, вероятно, это не так)

1

На странице Метод Dispatcher.BeginInvoke в MSDN:

В WPF только поток, создавший DispatcherObject может получить доступ к этому объекту

Поэтому, если вы сначала вызвали Dispatcher из своего фонового потока, тогда он может работать только в этом фоновом потоке. Вместо этого убедитесь, что вы инициализируете свой объект Dispatcher в потоке пользовательского интерфейса:

Dispatcher = Dispatcher.CurrentDispatcher;

На странице Dispatcher класс в MSDN:

Если вы попытаетесь получить CurrentDispatcher для текущего потока, и Dispatcher не связан с потоком, будет создан Dispatcher.

Затем, передав ссылку на этот Dispatcher потоков пользовательского интерфейса в фоновый поток, вы сможете снова получить доступ к потоку пользовательского интерфейса из фонового потока.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню