问题
i recently acquired some source code for a console wrapper for a server. The program was originaly in WPF and part of the code was:
private void ServerProc_ErrorDataReceived(object sender, DataReceivedEventArgs e)
{
Dispatcher.Invoke(new Action(() =>
{
ConsoleTextBlock.Text += e.Data + "\r\n";
ConsoleScroll.ScrollToEnd();
}));
}
private void ServerProc_OutputDataReceived(object sender, DataReceivedEventArgs e)
{
Dispatcher.Invoke(new Action(() =>
{
ConsoleTextBlock.Text += e.Data + "\r\n";
ConsoleScroll.ScrollToEnd();
ParseServerInput(e.Data);
}));
}
Its also had this annotation in both voids:
// You have to do this through the Dispatcher because this method is called by a different Thread
However in WinForms there is no such thing - is there a way to change this to a Background worker or something (Ive barely done any multi-threading)?
If anyone could help, that be great!
Thanks.
回答1:
Both methods are event handlers. Chances are they are from some kind of listening code and I would expect that they are called from a non UI thread (eg normally a threadpool thread that is doing the listening). You can check that by putting a break point and looking at the threads window in the debugger.
So you will need to apply the winforms way of updating the UI from a non UI thread.
If you search SO you should find quite a lot on how to do that. E.g
Updating UI from a different thread
How to update GUI from another thread in C#?
回答2:
Some background: A process that is running in a thread other than the UI thread is not allowed to access any UI controls directly. Your WPF ServerProc is running in a different thread than your UI which requires the Dispatcher
to help you communicate from the ServerProc thread back to the UI controls in your UI thread.
If your ServerProc -- in WPF or WinForms -- were running in the UI thread, you would not need to surround it with the Dispatcher.Invoke
call.
For you, you can put your ServerProc in a BackgroundWorker (MSDN example). Your DoWork
method would contain the meat of the code doing the work and then depending on how the ServerProc does its work, you might be able to use ProgressChanged
to do what both your sample WPF methods are doing. ProgressChanged
has a parameter passed in that you would indicate if it were an error or data has been received and inside the function you could display the appropriate info. Take a look at the MSDN docs because they have a good example.
What's important to point out is that ProgressChanged
happens on the UI thread so you do NOT need to surround your calls to your UI controls with Invoke; just call them normally. Same goes for RunWorkerCompleted
which may be the other option for displaying data when your ServerProc has finished its job.
Finally, if you actually had to access a UI control from within your thread, you do something very similar looking as your WPF code sample. Look at MethodInvoker. Instead of Dispatcher, you're really just calling it from your main Form.
来源:https://stackoverflow.com/questions/10054564/convert-a-wpf-dispatcher-to-winforms-bgworker