多线程上的 WPF UI?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/28313395/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-13 12:54:34  来源:igfitidea点击:

WPF UI on multiple threads?

c#wpfmultithreading

提问by Kelly

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.

我有一个大型 WPF MVVM 应用程序(目前有超过 100 个窗口并且还在不断增长。)尽管我尝试在后台线程上尽我所能,但总会有时间必须将结果发送回 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.

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

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

我知道随着 Windows 10 的到来,许多用户会在不同的桌面上打开更多的窗口,从而使情况变得更糟。

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?

任何人都知道如何让多个 UI 线程在 WPF 中正常工作?或者有任何我可以调查的信息来帮助我的应用程序在这条路上走得更远?

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

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

这是大约 2 年前的事了,不幸的是,我无法再回忆起我在使用它时遇到的所有问题。

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

还有其他方法吗?有没有人使用这种方法或另一种方法使具有许多窗口的应用程序正常工作?

回答by Peter Duniho

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()).

一般来说,它“有效”。您需要做的主要事情是将线程设置为 STA(如您的示例中所示)。但是,通过在不同线程中运行某些 UI,您获得的收益很少或一无所获。每个线程仍然可能被长时间运行的任务阻塞,因此您仍然需要在另一个线程中执行它们,并且您仍然存在需要某种封送回 UI 线程的跨线程问题(例如Dispatcher.Invoke())。

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 线程,现在您不仅需要跟踪哪个 UI 线程与哪个 UI 对象对应(因为它们仍然只能与拥有它们的线程一起使用),而且您将在 UI 方面遇到更多问题对象彼此交互,因为不同线程拥有的对象是互斥的。每个只需要在它拥有的线程中访问,所以让它们一起工作的唯一方法是创建某种代理系统来在线程之间来回传递数据和事件。

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

基本上,为 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/awaitfeature, 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.

幸运的是,从 .NET 4.5 和 C# 5.0 开始,有一些框架和语言功能可以极大地简化后台操作的处理以及将信息编组回 UI 线程。使用async/await功能,您可以使用框架功能(如Task<T>类或某些类方法(通常名称以单词结尾Async))启动异步操作,在操作期间不阻塞 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).

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

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. :)

因此,走 .NET 和 C# 鼓励您走的道路,避免走艰难的道路。将所有 UI 保留在一个线程中,并使用提供的工具解决出现的任何问题,而不是试图与 API 作斗争。:)