简体   繁体   English

c#wpf dispatcher.begin调用冻结

[英]c# wpf dispatcher.beginInvoke freeze

im working on an application which communicates with server. 我正在与服务器通信的应用程序上工作。

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)));

}

later i need to print result to a messagebox. 稍后我需要将结果打印到消息框。 I know i have to use Dispatcher, because im working in another thread, but my application freezes even if i use beginInvoke method. 我知道我必须使用Dispatcher,因为我在另一个线程中工作,但是即使我使用beginInvoke方法,我的应用程序也会冻结。

Edit based on Sheridan's answer : 根据Sheridan的答案进行编辑

now im getting: An unhandled exception of type 'System.InvalidOperationException' occurred in WindowsBase.dll 现在我正在获取:WindowsBase.dll中发生了类型为'System.InvalidOperationException'的未处理异常

Additional information: The calling thread cannot access this object because a different thread owns it. 附加信息:调用线程无法访问该对象,因为另一个线程拥有它。

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

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

and changed print method: 并更改了打印方法:

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

solved by using Application.Current.Dispatcher 通过使用Application.Current.Dispatcher 解决

Always be wary of Dispatcher.CurrentDispatcher as that will will return an object for dispatching on the CURRENT thread - which may not be the UI. 始终要警惕Dispatcher.CurrentDispatcher因为这将返回用于在CURRENT线程上分派的对象-可能不是UI。 You want (and generally almost always want) the UI thread dispatcher. 您想要(通常几乎总是想要)UI线程分派器。

You can get that through Application.Current.Dispatcher Which always returns the UI thread dispatcher. 您可以通过Application.Current.Dispatcher获得该信息,该Application.Current.Dispatcher始终返回UI线程分派器。

Its frustating that these calls looks so similar... 令人沮丧的是这些调用看起来如此相似...

[If you are in the main window you can just call Dispatcher but that probably not the case for you] [如果您在主窗口中,则可以仅致电Dispatcher但实际情况并非如此]

From the Dispatcher.BeginInvoke Method page on MSDN: 在MSDN上的Dispatcher.BeginInvoke方法页面上:

In WPF, only the thread that created a DispatcherObject may access that object 在WPF中,只有创建DispatcherObject的线程才能访问该对象

Therefore, if you first called the Dispatcher from your background thread, then it can only run on that background thread. 因此,如果您首先从后台线程调用Dispatcher ,则它只能在该后台线程上运行。 Instead of that, ensure that you 'initialise' your Dispatcher object on the UI thread: 而是要确保在UI线程上“初始化”您的Dispatcher对象:

Dispatcher = Dispatcher.CurrentDispatcher;

From the Dispatcher Class page on MSDN: 从MSDN上的Dispatcher Class页面:

If you attempt to get the CurrentDispatcher for the current thread and a Dispatcher is not associated with the thread, a Dispatcher will be created. 如果您尝试获取当前线程的CurrentDispatcher ,并且Dispatcher与该线程未关联,则将创建一个Dispatcher

Then passing a reference to that UI thread Dispatcher to your background thread will enable you to access the UI thread again from the background thread. 然后,将对该UI线程Dispatcher的引用传递给您的后台线程,将使您能够再次从后台线程访问UI线程。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM