WPF优化UI线程上的加载
我正在尝试优化我的WPF prism应用程序的加载时间。加载基本上是一个使用反射创建UI元素实例的循环,然后将它们添加到选项卡控件中的主窗口(shell) 由于我们仅限于使用一个线程来创建所有对象,那么加快加载/创建更好的用户体验的最佳方式是什么 到目前为止,我有以下几种选择:WPF优化UI线程上的加载,wpf,wpf-controls,prism,Wpf,Wpf Controls,Prism,我正在尝试优化我的WPF prism应用程序的加载时间。加载基本上是一个使用反射创建UI元素实例的循环,然后将它们添加到选项卡控件中的主窗口(shell) 由于我们仅限于使用一个线程来创建所有对象,那么加快加载/创建更好的用户体验的最佳方式是什么 到目前为止,我有以下几种选择: 使用延迟加载。仅在用户第一次单击选项卡时加载该选项卡。但当它按需初始化时,第一次打开时会有4-5秒的延迟 缓存所有反射调用。我确实这样做了,但它根本没有加快任何速度。大多数时间发生在控件的渲染过程中 ? 对于这个棘手的问
对于这个棘手的问题,如果您有任何建议,我们将不胜感激。我将实现一个计时器,在每次滴答(迭代)时加载几个控件或选项卡。计时器将在与UI相同的线程上运行(它的控制消息将在Windows消息循环中排队)。一旦所有的工作都完成了,你就可以停止计时了
计时器间隔和每次滴答加载的控件数量将缩减为使用测试;尝试使用100ms和2个控件之类的选项,一秒钟可以为您提供约20个控件,因此,如果您有10个选项卡,每个选项卡上有15个控件,则需要约8秒钟,但UI锁定不应如此糟糕。如您所述,如果您的对象是DependencyObjects,则无法执行多线程操作。这就是为什么您必须利用并执行POCO对象来保存数据。这样,您可以通过多线程获得数据,然后将这些数据绑定到您的UI。使用DependencyObjects的另一个缺点是将应用程序与WPF框架绑定得太多(DependencyObject是WPF程序集中System.Windows命名空间中定义的类(不记得是PresentationCore还是PresentationFramework))。如果重构不是一个选项,那么你必须考虑一个解决方案,就像一个LAST编码器所建议的那样。请注意,您将能够执行很少的多线程处理(如果有的话),因此您的应用程序不会一直都有很好的响应。由于只能在主线程上加载对象,因此我认为您不会让它加载得更快 你所能做的就是分散用户的注意力:我有一个动画启动屏幕,它需要大约10秒的时间来完成动画序列。这有很多目的:
public class AppEntry : Application
{
private static ManualResetEvent _resetSplashCreated;
internal static Thread SplashThread { get; set; }
internal static SplashWindow SplashWindow { get; set; }
private static void ShowSplash()
{
SplashWindow = new SplashWindow();
SplashWindow.Show();
_resetSplashCreated.Set();
Dispatcher.Run();
}
[STAThread]
public static void Main()
{
_resetSplashCreated = new ManualResetEvent(false);
SplashThread = new Thread(ShowSplash);
SplashThread.SetApartmentState(ApartmentState.STA);
SplashThread.IsBackground = true;
SplashThread.Name = "Splash Screen";
SplashThread.Start();
_resetSplashCreated.WaitOne();
var app = new App();
app.DispatcherUnhandledException += new DispatcherUnhandledExceptionEventHandler(app_DispatcherUnhandledException);
app.InitializeComponent();
app.Run();
}
static void app_DispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e)
{
// MessageBox.Show(e.Exception.StackTrace);
}
}
我在项目属性/应用程序选项卡中将AppEntry类设置为我的启动对象。我在应用程序中的OnStartup方法结束时关闭启动屏幕:
AppEntry.SplashWindow.Dispatcher.BeginInvoke(DispatcherPriority.Background,
new Action(() => AppEntry.SplashWindow.Close()));
这个快吗?不
用户认为它更快吗?对
有时,如果你不能给他们速度,你可以给他们活动。这是一个很好的安慰剂。加快加载速度的最佳方法是在构建可视化树时简单地隐藏容器 这可以防止屏幕不断需要自我更新 将所有元素添加到可视化树后,将“容器可见性”设置为“可见”将一次性渲染选项卡容器 我们还对选项卡控件项实现了一些简单的延迟渲染
最终结果:加载时间从2分钟减少到20秒左右。加载选项卡内容怎么可能需要4-5秒?涉及到什么?你看过这个吗@维基百科的核心“状态”是:“在计算机科学和自动机理论中,数字逻辑电路或计算机程序的状态是一个技术术语,指在给定时间点,电路或程序使用的所有存储信息。”这就是我的意思。不多也不少。示例代码不可用required@HighCore不是真的。要参与数据绑定,对象必须从dependencyObject继承。dependencyObjects必须与窗口所有者在同一线程上创建。正确的方法是创建只封装数据而不从dependencyObject继承的包装器对象。这种方法太麻烦了,因为每个可绑定类需要1:1的DTO。@HighCore感谢您的评论。我们已经考虑过InotifyProperty已更改。我正在寻找创造性/优雅的解决方案。如果没有,我可以接受。这是一个有趣的想法。我将尝试一下,并让你知道,如果该方法似乎有效。我以前从未这样做过,所以在尝试之前我不会知道。我们最终在加载过程中隐藏了tab容器。这是最优雅的解决方案,因为它阻止了UI不断地呈现自己。+1用于启动屏幕,使用户认为加载速度更快。@Speaker Solutions感谢您的建议和示例代码。我使用的是闪屏,但它没有那么灵敏,因为UI线程总是在旋转。在另一个线程上创建启动窗口的想法有其优点。我将尝试一些建议,然后再给你回复。谢谢这里需要记住的重要一点是,我们正在运行2个Dispatchers,因此当你的应用程序准备就绪时,你可以在splash窗口中做一些“漂亮”的事情。在我的例子中,我用blend拿着公司的图标并用它折纸。我如何授予部分学分?我也要感谢你的回应。再次感谢你的洞察力。我们确实有POCO对象,它们被用来洗牌数据。在将这些对象转换为我们在绑定中使用的(DependencyObjects)对象之前,它们的寿命往往很短。您的建议似乎表明我们应该将这些服务器对象保留更长时间。这可能是一个错误