Edited at

【WPF】仮想化キャンバスを使用したDataGridの描画高速化

本問題は解決済みです。結論のみ知りたい方はコチラまでスクロールをお願いします。


経緯

WPFはグラフィカルな描画に優れており、画面の詳細な設定に長けているが、レイヤー構造が多層化しているため、描画が非常に遅い。DataGridの描画だけ示すとFormApplicationのDataGridViewの方が大量のデータ表示に長けている。(過去のデータ表示アプリケーションでFormApplicationを採用していたのはそのため)


そもそもなぜ遅い?

DataGrid系のオブジェクトは以下の多段クラスで構成されている。


  • DataGridView

  • DataRow

  • DataColumn

  • DataCell

この構造による欠点は以下の通り。

* 画面表示時にDataCell分インスタンスを生成する必要がある

* 画面描画時にDataCell分描画処理が発生する

* オートサイズプロパティがあった場合、親の表示位置やサイズに合わせてサイズプロパティを動的に全DataCell分計算し描画し直す必要がある


FormApplicationではどうしてた?

過去に高速化のアプローチのために自分がFormApplication側で対応した実装一覧

* 描画に必要なメモリを軽量化するため、すべてのVisual系プロパティをオフ

* DataSourceの設定完了までオブジェクトを非表示化(動的に描画が変更されるのを防ぐため)

* 画面サイズ変更時・・(同上)

* 描画後の再配置が行われないようにDataColumn, DataRowのサイズを固定化


WPFではどうなった?

めっちゃ重い。

今回の実装の目標は10万件レベルのレコードもストレスなく使用できるグリッドの実装。

FormApplicationでのノウハウをすべてつぎ込んでも2倍程度しか早くならない…。

現実では一万件でもかなり重い。。。


ならばどうする?

WPFでの高速化アプローチを実践してみる!

仮想化Canvas

仮想化Canvasの素朴な機構イメージは、表示ボックスに交差して表示されるアイテムをインスタンス化し交差から外れたアイテムを廃棄する実装。

DataGrid等で画面外のインスタンスを生成せず、見えている範囲のみ描画する、ってこと。

以下、MS社員が作ったサンプルプログラム。これをベースにカスタムしていきます。

Virtualized WPF Canvas

https://blogs.msdn.microsoft.com/jgoldb/2008/03/09/virtualized-wpf-canvas/

実装結果は後日報告します!


追記

えーーー…調査したところDataGridにはデフォルトで仮想化プロパティが準備されているとのことで‥。

該当プロパティを設定したところ非常に高速化したので情報展開します。


○VirtualizingStackPanel.IsVirtualizingプロパティ:True
 UI仮想化用の添付プロパティ。VirtualizingStackPanel.VirtualizationModeプロパティとセット。
DataGridは内部でVirtualizingStackPanelが利用されているので、設定推奨、とぃうか必須。
 これがないと、DataGridはデータが増えれば増えるほど、駄目な子になります。

○VirtualizingStackPanel.VirtualizationModeプロパティ:Standard
 UI仮想化のモード。Standardは標準。Recyclingは視界から消えたコンテナ(DataGridRowかその中のPresenter系)を使いまわしている感じがする。
 メモリや速度に優しいのはRecycling。だけど、レイアウトが崩れまくるのもRecycling。特に行ヘッダに番号とか表示したら、もう大変。
 ソートとか、全体がリフレッシュされるまで崩れたままという…。

○EnableRowVirtualizationプロパティ
 縦(行)方向へのUI仮想化を有効にする。デフォルトでTrueになっている。VirtualizingStackPanelの添付プロパティをセットで使って、ようやくマシになる。
 ただし、このプロパティを動的に変更しようとすると、エラーになるらしい。
 WPF DataGrid: EnableRowVirtualization Property dynamics
 MSの見解:もっとやばいバグを先に直すよ!だから保留ネ。
 まあ、動的に変えようという意図があまり理解できないので、放っておくに限る。

○EnableColumnVirtualizationプロパティ
 列方向へのUI可能化を有効にする。DataGridがどうにももっさりする時は、これをTrueにするとマシになることがある。
 ただし、マシになるだけ。低スペックのPCだとやっぱりもっさりする。
 仕事上でこれをTrueにしたところ、複雑なStyleやTemplateと喧嘩するらしく、派手に落ちなさるので、Falseのままに。

出典:DataGridの基本的な事 - C#等と戯れる日々

http://tawamuredays.blog.fc2.com/blog-entry-71.html

WPFのノウハウがなくて右往左往してしまっていたんですが便利すぎますね。


参考

WPFアプリケーションを高速化、仮想化Canvasを使ってみた。

https://qiita.com/takanemu/items/6f9ea70a0b5425b67f75 #Qiita