c#wpf dispatcher.beginInvoke freeze

时间:2014-05-22 12:38:33

标签: c# wpf freeze dispatcher

我正在处理与服务器通信的应用程序。

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,因为我在另一个线程中工作,但即使我使用beginInvoke方法,我的应用程序也会冻结。

根据Sheridan的回答进行编辑

现在我得到: WindowsBase.dll

中出现未处理的“System.InvalidOperationException”类型异常

附加信息:调用线程无法访问此对象,因为另一个线程拥有它。

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

解决了

2 个答案:

答案 0 :(得分:4)

始终警惕Dispatcher.CurrentDispatcher,因为它将返回一个对象,用于在CURRENT线程上调度 - 可能不是UI。您想要(通常几乎总是想要)UI线程调度程序。

你可以通过Application.Current.Dispatcher获得它,它总是返回UI线程调度程序。

令人沮丧的是,这些电话看起来如此相似......

[如果你在主窗口,你只需拨打Dispatcher,但可能不是你的情况]

答案 1 :(得分:1)

来自MSDN上的Dispatcher.BeginInvoke Method页:

  

在WPF中,只有创建DispatcherObject的线程才能访问该对象

因此,如果您首先从后台线程调用Dispatcher,那么它只能在该后台线程上运行。而不是那样,确保在UI线程上“初始化”您的Dispatcher对象:

Dispatcher = Dispatcher.CurrentDispatcher;

来自MSDN上的Dispatcher Class页:

  

如果您尝试获取当前线程的CurrentDispatcher并且Dispatcher未与该线程关联,则将创建Dispatcher

然后将对该UI线程Dispatcher的引用传递给后台线程,这将使您能够从后台线程再次访问UI线程。