3

我正在尝试优化我的 WPF prism 应用程序的加载时间。加载基本上是一个循环,使用反射创建 UI 元素的实例,然后将它们添加到选项卡控件中的主窗口(外壳)。

由于我们仅限于使用单个线程来创建所有对象,那么加速加载/创建更好用户体验的最佳方式是什么?

这些是我到目前为止的选择:

  1. 使用延迟加载。仅在用户第一次单击它时加载选项卡。但这将在第一次打开时延迟 4-5 秒,因为它是按需初始化的。

  2. 缓存所有反射调用。我实际上是这样做的,但它根本没有加快任何速度。大多数时间发生在控件的渲染过程中......

  3. ?

对于这个棘手的问题,任何建议都将不胜感激。

4

4 回答 4

3

你几乎被卡住了,因为你只能在主线程上加载对象,所以我认为你不会让它加载得更快。

你可以做的是分散用户的注意力:我有一个动画启动屏幕,它需要大约 10 秒才能完成动画序列。这有多种用途:

  1. 它显示了用户的动作 - 所以他们有一个视觉提示,表明某事正在发生
  2. 它分散了他们的注意力并填充了初始负载所占用的空间

为确保动画流畅,您需要创建第二个调度程序。这是我的做法:

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 类设置为我的启动对象。
我在 App 中的 OnStartup 方法结束时关闭了初始屏幕:

 AppEntry.SplashWindow.Dispatcher.BeginInvoke(DispatcherPriority.Background,
                                                             new Action(() => AppEntry.SplashWindow.Close()));

这更快吗?否 用户是否认为它更快?是的

有时,如果你不能给他们速度,你可以给他们活动。这是一个很好的安慰剂。

于 2012-11-01T09:59:42.857 回答
2

正如你所提到的,如果你的对象是 DependencyObjects,你就不能多线程。Kent Boogart 讨论了这一点。这就是为什么您必须利用INotifyPropertyChanged并做 POCO 对象来保存你的数据。这样你就可以多线程来获取数据,然后将它们绑定到你的 UI。使用 DependencyObjects 的另一个缺点是您将应用程序过多地绑定到 WPF 框架(DependencyObject 是在 WPF 程序集的 System.Windows 命名空间中定义的类(不记得是 PresentationCore 还是 PresentationFramework))。如果重构不是一种选择,您将不得不考虑像 LastCoder 提出的解决方案。请注意,您将能够执行很少的多线程(如果有的话),因此您的应用程序不会一直响应非常快。

于 2012-11-01T01:12:51.783 回答
1

我会实现一个计时器,它会在每个滴答(迭代)时加载一些控件或选项卡。计时器将在与 UI 相同的线程上运行(它的控制消息将在 Windows 消息循环中排队)。完成所有工作后,您可以终止计时器。

计时器间隔和每个滴答要加载的控件数量将归结为使用测试;尝试像 100ms 和 2 个控件的滴答声,每秒将给您大约 20 个控件,因此如果您有 10 个选项卡,每个选项卡有 15 个控件,则需要大约 8 秒,但 UI 不应该锁定为糟糕。

于 2012-10-31T19:21:15.400 回答
1

加快加载速度的最佳答案是在构建可视化树时简单地隐藏容器。

这可以防止屏幕不断需要更新自身。

当所有元素都添加到可视化树中时,将容器可见性设置为可见会渲染选项卡容器一次。

我们还对选项卡控件项实现了一些简单的延迟渲染。

最终结果:加载时间从 2 分钟缩短到大约 20 秒。

于 2012-11-07T18:48:35.577 回答