3

WPFプリズムアプリケーションの読み込み時間を最適化しようとしています。ロードは基本的に、リフレクションを使用してUI要素のインスタンスを作成し、それらをタブコントロールのメインウィンドウ(シェル)に追加するループです。

すべてのオブジェクトを作成するために単一のスレッドを使用することに制限されているので、読み込みを高速化/より良いユーザーエクスペリエンスを作成するための最適な方法は何でしょうか?

これらは私がこれまでに持っているオプションです:

  1. 遅延読み込みを使用します。ユーザーが最初にタブをクリックしたときにのみタブをロードします。ただし、オンデマンドで初期化されるため、最初に開くのに4〜5秒の遅延があります。

  2. すべてのリフレクション呼び出しをキャッシュします。私は実際にそれをしました、しかしそれは何もスピードアップしませんでした。ほとんどの場合、コントロールのレンダリング中に発生します...

このトリッキーな問題について、どんな提案でも大歓迎です。

4

4 に答える 4

3

メインスレッドにしかオブジェクトをロードできないため、かなり行き詰まっています。したがって、これ以上速くロードすることはできないと思います。

あなたができることは、ユーザーの注意をそらすことです。アニメーションのスプラッシュ画面があり、アニメーションシーケンスを実行するのに約10秒かかります。これには多くの目的があります。

  1. それはユーザーの動きを示しています-それで彼らは何かが起こっているという視覚的な手がかりを持っています
  2. それはそれらの気をそらし、初期負荷によって占められたスペースを埋めます

スムーズなアニメーションを確保するには、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クラスを設定しました。
アプリのOnStartupメソッドの最後でスプラッシュ画面を閉じます。

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

これは速いですか?いいえユーザーはそれが速いと思いますか?はい

時々、あなたが彼らにスピードを与えることができないならば、あなたは彼らに活動を与えることができます。それは素晴らしいプラセボです。

于 2012-11-01T09:59:42.857 に答える
2

前述のように、オブジェクトがDependencyObjectsの場合、マルチスレッド化することはできません。KentBoogartがこれについて説明しています。そのため、 INotifyPropertyChangedを活用する必要がありますデータを保持するためにPOCOオブジェクトを実行します。このようにして、マルチスレッドでデータを取得し、それらをUIにバインドできます。DependencyObjectsを使用するもう1つの欠点は、アプリケーションをWPFフレームワークに結び付けすぎていることです(DependencyObjectは、WPFアセンブリのSystem.Windows名前空間で定義されているクラスです(PresentationCoreまたはPresentationFrameworkのどちらであるかを覚えていないでください))。リファクタリングがオプションでない場合は、LastCoderが提案したようなソリューションを検討する必要があります。マルチスレッドをほとんど実行できないことに注意してください(あるとしても)。したがって、アプリケーションは常に応答性が高くなるとは限りません。

于 2012-11-01T01:12:51.783 に答える
1

ティックごとにいくつかのコントロールまたはタブをロードするタイマーを実装します(反復)。タイマーはUIと同じスレッドで実行されます(タイマーの制御メッセージはWindowsメッセージループでキューに入れられます)。すべての作業が完了したら、タイマーを強制終了できます。

タイマー間隔とティックごとにロードするコントロールの数は、使用テストに要約されます。100ミリ秒と2つのコントロールのようなものを試してみてください。1秒間に最大20のコントロールが得られるので、それぞれ15のコントロールを持つ10のタブがある場合、最大8秒かかりますが、UIはそれほど悪くはありません。

于 2012-10-31T19:21:15.400 に答える
1

読み込みを高速化するための最良の答えは、ビジュアルツリーの構築中にコンテナを非表示にすることです。

これにより、画面が常に更新される必要がなくなります。

すべての要素がビジュアルツリーに追加されたら、コンテナの可視性を可視に設定すると、タブコンテナが1回レンダリングされます。

また、タブコントロールアイテムにいくつかの単純なレイジーレンダリングを実装しました。

最終結果:読み込み時間は2分から約20秒になります。

于 2012-11-07T18:48:35.577 に答える