Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/wpf/13.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/symfony/6.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
WPF优化UI线程上的加载_Wpf_Wpf Controls_Prism - Fatal编程技术网

WPF优化UI线程上的加载

WPF优化UI线程上的加载,wpf,wpf-controls,prism,Wpf,Wpf Controls,Prism,我正在尝试优化我的WPF prism应用程序的加载时间。加载基本上是一个使用反射创建UI元素实例的循环,然后将它们添加到选项卡控件中的主窗口(shell) 由于我们仅限于使用一个线程来创建所有对象,那么加快加载/创建更好的用户体验的最佳方式是什么 到目前为止,我有以下几种选择: 使用延迟加载。仅在用户第一次单击选项卡时加载该选项卡。但当它按需初始化时,第一次打开时会有4-5秒的延迟 缓存所有反射调用。我确实这样做了,但它根本没有加快任何速度。大多数时间发生在控件的渲染过程中 ? 对于这个棘手的问

我正在尝试优化我的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)对象之前,它们的寿命往往很短。您的建议似乎表明我们应该将这些服务器对象保留更长时间。这可能是一个错误