预加载WPF窗口(可能在其他线程中)以提高性能

时间:2011-06-09 16:36:23

标签: c# wpf windows multithreading performance

我有一个WPF窗口需要花费大量时间来创建和显示。用户应该能够打开一个或多个这个窗口。 现在,我正在寻找一种提高性能的方法。一个想法是在应用程序启动时创建两个Windows(当它显示启动画面时)。我只需要显示和隐藏这个窗口(并更改附加的viewmodel)。这应该不是问题。但是当用户使用应用程序并且他使用在应用程序启动时加载的两个窗口时,我应该在后台加载窗口的第三个实例。现在,应用程序不应该在加载第三个应用程序(或4. oder 5.等)时被阻止。现在,我正在寻找一种方法来做到这一点。是否可以在另一个线程中加载窗口并将其传输到主UI线程? 还是有其他方案可以达到目标吗?

感谢您的帮助。

最诚挚的问候,托马斯

6 个答案:

答案 0 :(得分:6)

我有一个辅助wpf窗口需要花费很长时间(2秒)才能在第一次显示时打开,并且在后续加载时花费很少时间。事实证明这是由于加载了扩展的工具包程序集(以及其他一些程序集)。为了解决这个问题,我在App.xaml.cs中添加了以下内容:

        var thread = new Thread(() =>
        {//Force runtime to pre-load all resources for secondary windows so they will load as fast as possible
            new SecondaryForm1();
            new SecondaryForm2();
        });
        thread.SetApartmentState(ApartmentState.STA);
        thread.Priority = ThreadPriority.Lowest;//We don't want prefetching to delay showing of primary window
        thread.Start();
        //Now start primary window

在更改之后,辅助窗口将在大约10毫秒内首次显示。我起初并不喜欢冗余实例化的外观,但实际上......有什么危害?还有很多其他的东西可能会延迟新窗口的显示,但这肯定值得一试。我从this question得到了这个想法。

答案 1 :(得分:5)

当你创建一个WPF对象 - WindowUserControl,或其他任何东西,从DispatcherObject下降 - 其锁定自己创建它的线程。因此,您无法在后台线程中加载窗口,然后将其传输到主UI线程。如果你要在后台线程中创建它,它需要留在那个线程上;它需要由该线程显示,并在该线程上有一个消息泵。

但那是可行的。您可以启动后台线程,在那里创建窗口,然后等待主线程说“好的,是时候显示窗口”。然后你的线程可以调用Application.Run来启动自己的消息泵,并在窗口关闭时自行关闭。

当然,多线程开辟了各种新的并发症。您可能需要为每个窗口提供一个专用线程(线程池不太可能适用于此)。您需要处理所有线程间通信。如果Windows访问任何共享数据,您需要通过某种锁定来保护它。您需要确保应用程序退出时,它应该(如果这意味着“当所有的窗口都关闭”,那么你需要确保你保护“打开的窗口数”资源)。也可能有其他并发症。不要轻易进入。

正如其他人所说,您最好的选择是分析您的代码并尝试首先解决您的性能问题。但是,你尽可能多的性能完成工作,如果你相信你可以,多线程和后台加载可以探索的一个选项。

答案 2 :(得分:4)

也许你正试图从错误的方面解决问题?我认为你应该做长时间运行的操作,导致Windows挂在后台,而不是尝试在后台运行Windows。您可以立即为用户显示窗口,然后显示一些不错的动画,而后台线程通过检索数据/计算某些内容等来完成工作。也许我误解了你的问题

答案 3 :(得分:1)

我认为这不可能,因为WPF应用程序只有一个UI线程。

是否需要花费一段时间才能加载或填充虚拟机中的GUI元素?如果它是VM中的内容,您可以尝试在另一个线程上创建VM并将其带入...

答案 4 :(得分:1)

如果我是你,我会从分析你的应用程序开始,看看在窗口启动期间真正需要花时间。正如你所知,没有办法在其他线程中创建GUI并在主线程中使用它,但如果你有任何统计数据,我们可以尝试找出其他东西可以并行或缓存。

答案 5 :(得分:1)

密切关注塔拉斯所说的话。通常,诸如winforms和wpf之类的技术在创建UI方面足够快。当您看到慢速界面时,请仔细检查您自己的代码: 您是否正在加载数万行(然后使用分页)。 你在调用一个慢速方法(异步调用它) 你打电话给数据库或网络吗? (bach调用或将它们放在另一个线程上)

如果你在与上面列表类似的任何事情上失败,请回到你目前尝试做的事情。

相关问题