在多个线程上的WPF UI? [英] WPF UI on multiple threads?

查看:536
本文介绍了在多个线程上的WPF UI?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个大型WPF MVVM应用程序(当前有100多个窗口,并且还在不断增加.)尽管我尝试在后台线程上做所有我能做的事情,但是总有一段时间必须将结果发送回UI线程进行显示.当您有多个窗口同时执行此操作时,会影响性能.

I have a large WPF MVVM application (over 100 windows currently and growing.) Although I try to do everything I can on background threads there always comes a time the results must be sent back to the UI thread to be displayed. When you have many windows doing this at the same time it can effect performance.

过去,我尝试在单独的UI线程上运行每个窗口,但是遇到了很多线程问题,我不得不恢复为WPF的默认模型,即每个应用程序只有1个UI线程.

I've tried to run each window on a separate UI thread in the past but ran into so many threading issues I had to revert back to WPF's default model of only 1 UI thread per app.

我知道随着Windows 10的到来,许多用户将在单独的桌面上打开甚至更多的窗口,从而使情况变得更糟.

I know with windows 10 coming many users will open even more windows on separate desktops and thus make this worse.

任何人都知道如何使多个UI线程在WPF中正常工作吗?还是有任何我可以调查的信息来帮助我的应用进一步发展?

Anyone know how to get multiple UI threads to work correctly in WPF? Or have any info I can investigate to help get my app further down this road?

我过去尝试过的方法是做类似的事情:

I approach I tried in the past was to do something similar to this:

private void OnCreateNewWindow(
   object sender,
   RoutedEventArgs e)
  {
   Thread thread = new Thread(() =>
    {
     Window1 w = new Window1();
     w.Show();

     w.Closed += (sender2, e2) =>
      w.Dispatcher.InvokeShutdown();

     System.Windows.Threading.Dispatcher.Run();
    });

   thread.SetApartmentState(ApartmentState.STA);
   thread.Start();
  }

大约2年前,不幸的是,我再也无法回忆起我所遇到的所有问题.

This was about 2 years ago and I can no longer recall all the issues I faced using this unfortunately.

还有另一种方法吗?是否有人使用这种方法或其他方法获得了具有许多窗口的应用程序才能正常工作?

Is there another way? Has anyone gotten an app with many windows to work correctly using this approach or another?

推荐答案

通常,它有效".您要做的主要事情是将线程设置为STA(如您的示例所示).但是,通过在不同的线程中运行某些UI,您几乎不会获得任何收益.每个线程仍然可能被长时间运行的任务阻塞,因此您仍然需要在另一个线程中执行那些任务,并且仍然存在跨线程问题,需要某种形式的封送处理返回给UI线程(例如Dispatcher.Invoke()).

In general, it "works". The main thing you have to do is set the thread to STA (as in your example). But you gain little or nothing by running some of the UI in a different thread. Each thread can still be blocked by long-running tasks, so you still need to execute those in yet another thread, and you still have the cross-thread issue requiring some kind of marshaling back to the UI thread (e.g. Dispatcher.Invoke()).

此外,拥有多个UI线程,现在不仅要跟踪哪个UI线程与哪个UI对象一起使用(因为它们仍然只能与拥有它们的线程一起使用),所以您将拥有更多UI对象彼此交互的问题,因为不同线程拥有的对象是互斥的.每个对象都仅需要在其拥有的线程中进行访问,因此使它们一起工作的唯一方法是创建某种代理系统,以在线程之间来回传递数据和事件.

Furthermore, with more than one UI thread, now not only do you have to keep track of which UI thread goes with which UI object (since they still can be used only with the thread that owns them), you will have more problems with UI objects interacting with each other, because those owned by different threads are mutually exclusive. Each is required to be accessed only in the thread in which it's owned, so the only way to have them work together is to create some kind of proxy system to pass data and events back and forth between threads.

基本上,为UI创建多个线程从来都不是一个好主意.

Basically, it never was and still is not a good idea to create more than one thread for the UI.

幸运的是,从.NET 4.5和C#5.0开始,有一些框架和语言功能极大地简化了后台操作的处理以及将信息编组回UI线程的过程.使用async/await功能,您可以使用框架功能(如Task<T>类或某些类方法(通常名称以单词Async结尾))启动异步操作,并在整个过程中不阻塞UI线程.操作,并且可以轻松编写代码以处理操作结束时必须完成的任何工作.

Fortunately, as of .NET 4.5 and C# 5.0, there are framework and language features that greatly simplify the handling of background operations and the marshaling of information back to the UI thread. With the async/await feature, you can initiate asynchronous operations with framework features like the Task<T> class or certain class methods (usually with names ending in the word Async), have the UI thread unblocked for the duration of the operation, and yet easily write code to handle whatever work has to be done at the end of the operation.

还有Progress<T>类,该类以方便处理UI进度更新的方式实现IProgress<T>接口,即在UI线程上调用回调(只要您创建Progress<T> UI线程中的实例).

There is also the Progress<T> class, which implements the IProgress<T> interface in a way that is convenient for dealing with UI progress updates, i.e. invokes the callback on the UI thread (as long as you create the Progress<T> instance in the UI thread, of course).

因此,请采用.NET和C#鼓励您采用的方法,并避免使用困难的方法.将您的所有UI放在一个线程中,并使用提供的工具解决所有问题,而不是尝试使用API​​. :)

So, take the path that .NET and C# are encouraging you to take, and avoid the one that is hard. Keep all your UI in a single thread, and solve whatever issues come up using the tools provided instead of trying to fight the API. :)

这篇关于在多个线程上的WPF UI?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆