知覚されたWPFアプリの起動時間を改善します
-
12-10-2019 - |
質問
WPFデータベースビューアーアプリケーションがあります。これは、SQLiteデータベースから抽出されたデータを示すデータグリッドを備えたユーザーコントロールを含むシンプルなメインウィンドウです。
問題は、このアプリケーションが使用可能になるまで6秒かかることです。
メインウィンドウのコンストラクターでユーザーコントロールを構築し(およびすべてのデータロードを実行する)試みました。
この方法では、スプラッシュ画面に5Sが表示され、その後、アプリケーションを使用する準備ができるまで1の空のメインウィンドウが表示されます。
ユーザーは、何かが(視覚的に)起こるまで長すぎると言いました。
次に、ユーザーコントロールの作成(およびデータロード)をメインウィンドウのロードされたイベントハンドラーに移動しました。スプラッシュ画面に3秒が表示され、その後、アプリケーションが準備が整うまで3秒の空のメインウィンドウが表示されます。
ユーザーは「より良い」と言ったが、半分のメインウィンドウが障害状態に長い間表示されているという事実が気に入らない。
認識されているアプリケーションの負荷時間について見つけるべき一般的なアドバイスはありますか、それともこの状況をどのように改善できるかについて他の推奨事項はありますか?
理想的には、メインウィンドウは、データが読み込まれるまで、いくつかの時間ガラスまたはスピナーとともに、できるだけ速く表示されると思います。しかし、これは間違ったスレッドで行われるため、ユーザーコントロールの作成をバックグラウンドワーカーに移動することはできません。
誰かがこの問題について何か提案をしていますか?
編集:
現在、GridデータソースとしてLINQ-to-EFクエリを割り当てたばかりであることに注意してください。
考えられる改善の1つは、このデータをバックグラウンドのデータテーブルにロードし、ロードされた1回だけ割り当てることです...
edit2:system.data.sqliteとef4を使用して.net 4を使用してデータを読み込みます。多かれ少なかれ4000行と30列があります。
解決
データを非同期ロードします。ロード中にユーザーのGUIに何か素晴らしいものを提示します。次のコードはこれであなたを助けることができます:
BackgroundWorker bgWorker = new BackgroundWorker() { WorkerReportsProgress=true};
bgWorker.DoWork += (s, e) => {
// Load here your file/s
// Use bgWorker.ReportProgress(); to report the current progress
};
bgWorker.ProgressChanged+=(s,e)=>{
// Here you will be informed about progress and here it is save to change/show progress.
// You can access from here savely a ProgressBars or another control.
};
bgWorker.RunWorkerCompleted += (s, e) => {
// Here you will be informed if the job is done.
// Use this event to unlock your gui
};
bgWorker.RunWorkerAsync();
アプリは高速ではありませんが、GUIがすぐに見えるようになり、応答性が高いため、はるかに高速のようです。また、残りをロードしながら、ユーザーにロードされたデータの一部を表示することもできます。使用 ProgressChanged
- これを行うためのイベント。
アップデート
あなたの問題を正しく理解しているかどうかはわかりません。問題がない場合は、データをロードする必要がある場合、アプリケーションで何かが奇妙です。 WPFはIMO非常に高速です。制御作成には多くの時間はかかりません。いくつかのミリ秒で言及しているように、私ははるかに大きなリストを視覚化します。
datagridを妨げるものをUIに持っているものがあるかどうかを見てみてください。アイテムを仮想化してください。たぶん、あなたはそこにプロプレムを持っています。 WPFアプリを分析するには、お勧めします WPFプロファイリングツール.
他のヒント
あなたができる最も明白なことは、アプリケーションをプロファイルし、起動時にボトルネックを見つけることです。最も可能性の高い犯人は、データベースからのデータの読み込みであるように聞こえます。
私が学んだ教訓の1つは、ORMを使用している場合、ORMで生成されたデータベースエンティティ(以下の例を参照)よりもPoco(プレーン古いCLR/C#オブジェクト)を好む場合、大きなデータセットをロードする場合、ロード時間は大量に速くなり、RAMの使用も大幅に減少します。その理由は、EFがエンティティ全体(つまり、すべてのフィールド)と、おそらくあなたのエンティティに関連するデータ全体をロードしようとするためです。エンティティと直接作業する必要があるのは、挿入/更新/削除操作を行っているときだけです。データを読むときは、そうする必要があります それだけ アプリケーションが表示および/または検証するために必要なフィールドを取得します。
MVVMパターンに従う場合、上記のアーキテクチャを実装するのは難しくありません。
EFを使用してPOCOSにデータをロードする例:
var query = from entity in context.Entities
select new EntityPoco
{
ID = entity.ID,
Name = entity.Name
};
return query.ToList();
Pocosは、各フィールドに自動プロパティを備えた非常にシンプルなクラスです。
通常、アプリケーションに各エンティティのリポジトリがあり、各リポジトリはそのエンティティに関連するデータを取得/更新する責任があります。ビューモデルには、必要なリポジトリへの参照があるため、EFを直接使用しません。ユーザーが持続する必要がある変更を行うと、リポジトリ内の他のメソッドを使用して、エンティティのサブセットのみをロードし(つまり、ユーザーが変更したもの)、必要な更新を適用します。制約/トリガーなどを介してDBで進行します。
これには多くの理由があります。
1)展開マシンの構成はかなり低い場合があります。
2)データバインディングのインポーパーまたは問題。
可能な解決策は次のとおりです。
1)怠zyデータをロードします
2)パフォーマンスを最適化します。 http://msdn.microsoft.com/en-us/library/aa970683.aspx
アプリケーションがWPFで1秒未満の5Mレコードをレンダリングするのを見ていました。
PS:列の注文アクセスにより、1つの最小限の理由が30列になる場合があります。