【入門編】【中級者・実務】WPFのDataGridパフォーマンス最適化:大量行データを扱う際の仮想化(UI Virtualization)設定 – Visual Basic (VB / VB.NET)解析バイブル

スポンサーリンク
スポンサーリンク

【極限の知見】数万件のデータも瞬時に表示。WPF DataGridの「UI仮想化」を完全に掌握する

こんにちは。現場の設計から実装まで、泥臭くも美しいコードを追求し続けているチーフアーキテクトです。

Excel VBAのマクロから一歩踏み出し、Visual Basic (VB.NET) と WPF を使ったモダンなデスクトップアプリ開発に挑戦している皆さん。素晴らしいステップアップですね!

しかし、学習を進めていく中で、こんな「壁」にぶつかったことはありませんか?

> 「数千件、数万件のデータを DataGrid に表示しようとしたら、アプリが固まった……」
> 「メモリ使用量が急激に増えて、PCの動作が重くなった……」

実はこれ、プログラムのロジックが間違っているのではなく、「UI(見た目)の作り方」の設計思想を知らないために起こる、典型的な現象なんです。

今日は、プロフェッショナルへの登竜門とも言える「UI Virtualization(UI仮想化)」という概念を、VB.NETの実務レベルで徹底解説します。ここをマスターすれば、あなたは「ただ動くコード」を書く人から、「大規模データにも耐えうるプロのエンジニア」へと進化できますよ。

1. なぜ DataGrid は「重く」なるのか?

まず、敵の正体を知りましょう。

例えば、10万件のレコード(行)があるとします。もし WPF が「10万個の行(UI要素)」をすべてメモリ上に作り出し、画面に見えていない部分まで描画しようとしたらどうなるでしょうか?

1. メモリの枯渇: 1行ごとにテキストボックスやラベルなどの「オブジェクト」が生成されます。10万個ものオブジェクトは、メモリを凄まじい勢いで食いつぶします。
2. 描画の停滞: Windowsが「10万行分をどう描画するか」を計算しようとして、CPUが悲鳴を上げます。これが「カクつき」の正体です。

「データ」はただの数字の羅列ですが、「UI要素」は重たいオブジェクトなのです。

これを解決するのが、UI Virtualization(UI仮想化)。
「今、画面に見えている範囲の行だけを生成し、スクロールに合わせて使い回す」という、極めて賢い戦略です。

2. 勝利の方程式:VirtualizingStackPanel を使いこなす

WPFの `DataGrid` は、標準で仮想化機能を持っています。しかし、「正しく設定」しなければ、その力は発揮されません。

ここで覚えておいてほしい、最強の設定項目が3つあります。

① `IsVirtualizing=”True”`

これは「仮想化を有効にする」というスイッチです。通常はデフォルトで True ですが、明示的に意識することが大切です。

② `VirtualizationMode=”Recycling”`(★最重要!)

ここがプロの分かれ道です。

  • Standard(標準): スクロールして行が画面外に出たら、その行オブジェクトを破棄し、新しい行が入ってきたら新しく作り直す。
  • Recycling(再利用): スクロールして行が画面外に出たら、そのオブジェクトを捨てずに、中身のデータだけ書き換えて再利用する。

「作り直す」より「使い回す」ほうが、圧倒的に速い。 大量データを扱うなら、必ず `Recycling` を選択してください。

③ `ScrollUnit=”Pixel”`

デフォルトでは「行単位」でスクロールしますが、これだとスクロールが「ガクッ、ガクッ」と段差のように感じられます。`Pixel` を指定すると、滑らかなスクロールが可能になります。

3. 【実践】完璧な DataGrid の実装コード

では、実際に VB.NET と XAML を使って、数万件でも爆速で動く DataGrid を構築してみましょう。

XAML(見た目の定義)

ここでのポイントは、`DataGrid` のプロパティ設定です。

<!-- MainWindow.xaml -->
<Window x:Class="MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="High Performance DataGrid" Height="450" Width="800">
    
    <Grid>
        <!-- 
            DataGridのパフォーマンス設定
            1. VirtualizingStackPanel.IsVirtualizing: 仮想化を有効化
            2. VirtualizingStackPanel.VirtualizationMode: オブジェクトを破棄せず「再利用」する(爆速の秘訣)
            3. VirtualizingStackPanel.ScrollUnit: 行単位ではなく「ピクセル単位」で滑らかにスクロール
        -->
        <DataGrid x:Name="myDataGrid" 
                  ItemsSource="{Binding MyDataList}"
                  AutoGenerateColumns="True"
                  IsReadOnly="True"
                  VirtualizingStackPanel.IsVirtualizing="True"
                  VirtualizingStackPanel.VirtualizationMode="Recycling"
                  VirtualizingStackPanel.ScrollUnit="Pixel">
        </DataGrid>
    </Grid>
</Window>

VB.NET(ロジックの定義)

大量のデータを生成し、DataGridに流し込むコードです。

' MainWindow.xaml.vb
Imports System.Collections.ObjectModel

''' <summary>
''' データのモデルクラス(1行分のデータ)
''' </summary>
Public Class RecordModel
    Public Property Id As Integer
    Public Property Name As String
    Public Property Value As Double
End Class

Class MainWindow
    ''' <summary>
    ''' DataGridにバインドするためのコレクション
    ''' ObservableCollectionを使うことで、データの追加・削除をUIに通知できます
    ''' </summary>
    Public Property MyDataList As ObservableCollection(Of RecordModel)

    Public Sub New()
        ' WPFの初期化
        InitializeComponent()

        ' 1. データの準備
        MyDataList = New ObservableCollection(Of RecordModel)()

        ' 2. テスト用に10万件のデータを生成(これが重い処理のシミュレーション)
        GenerateDummyData(100000)

        ' 3. DataContext(データの出所)を自分自身に設定
        Me.DataContext = Me
    End Sub

    ''' <summary>
    ''' ダミーデータの生成メソッド
    ''' </summary>
    ''' <param name="count">生成する件数</param>
    Private Sub GenerateDummyData(count As Integer)
        For i As Integer = 1 To count
            MyDataList.Add(New RecordModel With {
                .Id = i,
                .Name = $"ユーザー_{i:D5}",
                .Value = i * 1.23
            })
        Next
    End Sub
End Class

4. 【要注意】初心者が陥る「仮想化が無効化される罠」

ここからが、設計者としての「知見」です。
どれだけ XAML で `IsVirtualizing=”True”` と書いても、ある特定のコントロールの中に DataGrid を入れてしまうと、仮想化は完全に死にます。

💀 恐怖の `StackPanel` 罠

例えば、以下のようなレイアウトを書いていませんか?

<!-- ❌ ダメな例:仮想化が効かない! -->
<ScrollViewer>
    <StackPanel>
        <TextBlock Text="データ一覧" FontSize="20"/>
        <DataGrid ItemsSource="{Binding MyDataList}" ... />
    </StackPanel>
</ScrollViewer>

なぜダメなのか?
`StackPanel` は、その中にある子要素に対して「君たちは好きなだけ縦に伸びていいよ!」という指示を出します。
すると DataGrid は、「お、無限に高さがあるなら、全行分(10万行)の UI 要素を全部作っちゃおう!」と判断してしまうのです。

結果として、仮想化(必要な分だけ作る)が機能せず、メモリ爆食い・フリーズが発生します。

✅ 解決策

DataGrid を配置する際は、「高さが制限されている親要素」の中に配置してください。

  • `Grid` (RowDefinition で高さを指定したもの)
  • `DockPanel`
  • `DataGrid` 自体の `Height` を指定する

「親が無限の広さを許可したら、仮想化は死ぬ」と覚えておきましょう。

まとめ:ここをクリアすれば、あなたはもう一人前です

今日の要点を振り返りましょう。

1. UI要素は重い: データそのものよりも、それを表示する「行オブジェクト」がメモリを圧迫する。
2. Recyclingが鍵: `VirtualizationMode=”Recycling”` を使い、オブジェクトを使い回して負荷を最小限にする。
3. 親要素に注意: `StackPanel` の中に DataGrid を入れると、仮想化が効かなくなる。

いかがでしたか?
「なぜ動かないのか」という現象の裏側にある、オブジェクトのライフサイクルと描画の仕組み。これを知ることで、あなたの書くコードは劇的に強固になります。

一歩ずつ、確実に。
この知識を武器に、素晴らしいアプリケーションを作り上げてください。応援していますよ!

タイトルとURLをコピーしました