0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

WinFormsに「WPFの表現力」を添える。ElementHostとXAMLで実現する、レガシー業務アプリの超高速・高機能化

0
Posted at

はじめに

WinFormsで長年運用されている業務システムにおいて、「1レコードを複数行で表示したい」「セル内で複雑な装飾をしたい」といった要望に直面したことはないでしょうか?
WinForms標準のDataGridViewでこれらを実現しようとすると、オーナー描画(OnPaint)の泥沼にハマることになります。

本記事では、WinFormsの基盤を活かしつつ、表示が複雑なグリッド部分だけを**WPF(ElementHost)**へ差し替えることで、開発効率とユーザー体験を劇的に向上させる手法を紹介します。

注意

この記事の作成には生成AIを使用しています。


1. 課題:WinForms標準グリッドの限界

例えば、以下のような明細表示を求められた場合、WinFormsでは実装の難易度が跳ね上がります。

  • 1行に複数の項目を2段、3段に分けて表示する
  • 明細の状態(ステータス)ごとに背景色や文字色を細かく制御する
  • 大量データ(数万件)を扱いながら、スムーズなスクロールを実現する

これをWPFのListViewDataTemplateに任せることで、宣言的に(XAMLで)美しく記述できるようになります。


2. 実装:WinFormsからWPFをホストする

全体の構造は以下のようになります。WinForms プロジェクトが WPF のライブラリを参照し、ElementHost を介して View と ViewModel を結合します。

WinForms側のコード

デザイナー任せにせず、コンストラクタでViewModelと共に注入するのが疎結合に保つコツです。

public partial class HybridForm : Form
{
    private DetailListViewModel _viewModel;

    public HybridForm(DataEntity entity)
    {
        InitializeComponent();

        // 1. ViewModelの生成
        _viewModel = new DetailListViewModel();

        // 2. WPFコントロールの生成と注入
        // DataContextを介してデータを渡す
        var wpfControl = new WpfDetailControl { DataContext = _viewModel };
        elementHost.Child = wpfControl;

        // 3. データの詰め替え(WinFormsエンティティ -> WPF ViewModel)
        BindData(entity);
    }

    private void BindData(DataEntity entity)
    {
        _viewModel.Items.Clear();
        foreach (var detail in entity.Details)
        {
            _viewModel.Items.Add(new ItemViewModel {
                Code = detail.Code,
                Name = detail.Name,
                Value = detail.Value,
                // ... 他の項目
            });
        }
    }
}

データフローをシーケンスで見ると、WinForms がデータの「詰め替え役」として動いていることが分かります。


3. 表現力のキモ:XAMLによる多段レイアウト

WPFなら、1レコードを複数行に跨いで表示するのもGridの定義次第です。

WpfDetailControl.xaml (抜粋)

<ListView ItemsSource="{Binding Items}">
    <ListView.ItemTemplate>
        <DataTemplate>
            <Grid Height="44">
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="120" /> <!-- コード用 -->
                    <ColumnDefinition Width="*" />   <!-- 名称用 -->
                </Grid.ColumnDefinitions>
                <Grid.RowDefinitions>
                    <RowDefinition Height="22" />
                    <RowDefinition Height="22" />
                </Grid.RowDefinitions>

                <!-- 1段目:識別コードや日付など -->
                <Border Grid.Row="0" Grid.Column="0" Style="{StaticResource CellBorderStyle}">
                    <TextBlock Text="{Binding Code}" />
                </Border>
                
                <!-- 2段目:名称(ColumnSpanで横いっぱいに表示) -->
                <Border Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2" Style="{StaticResource CellBorderStyle}">
                    <TextBlock Text="{Binding Name}" FontWeight="Bold" />
                </Border>
            </Grid>
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>

4. 高速化のロジック:仮想化とスクロール制御

大量の明細をストレスなく表示するために、WPFの「UI仮想化」を最大限に引き出します。

仮想化の設定

ListViewに以下のプロパティを設定することで、画面に見えている範囲の要素だけを生成し、メモリ消費と描画負荷を抑えます。

<ListView
    ItemsSource="{Binding Items}"
    VirtualizingStackPanel.IsVirtualizing="True"
    VirtualizingStackPanel.VirtualizationMode="Recycling"
    VirtualizingStackPanel.ScrollUnit="Pixel"> <!-- ここが重要! -->
</ListView>
  • IsVirtualizing="True": 仮想化を有効化。これがないとデータ件数に比例してパフォーマンスが低下します。
  • VirtualizationMode="Recycling": 生成したアイテムコンテナを再利用します。スクロール時のメモリ確保(GC)を減らすための必須設定です。
  • ScrollUnit="Pixel": ここがUX向上の最大のポイントです。 デフォルトの「項目単位(1行ずつカクカク動く)」ではなく「ピクセル単位」でスクロールさせることで、非常に滑らかでモダンな操作感になります。

5. デザインのTips:罫線を綺麗に見せる「負のマージン」

WPFでBorderを並べると、隣り合う境界線が重なって太く見える問題があります。業務アプリらしい精緻な0.5px〜1pxの線を実現するには、負のマージンを活用します。

<Style x:Key="CellBorderStyle" TargetType="Border">
    <Setter Property="BorderBrush" Value="Gray" />
    <Setter Property="BorderThickness" Value="0.5" />
    <!-- 上と左に負のマージンを設定して、隣のセルの線とわざと重ね合わせる -->
    <Setter Property="Margin" Value="-0.5,-0.5,0,0" />
</Style>

このわずかな工夫で、高解像度ディスプレイでもボヤけない、非常にシャープなグリッドが完成します。


まとめ:なぜこの構成が「強い」のか

従来の WinForms 単体構成と比較して、ハイブリッド化には明確なメリットがあります。

  1. 段階的移行が可能: 画面全体を書き換えるコストをかけず、ボトルネックとなっている「明細」だけをモダン化できる。
  2. デザイナーとロジックの分離: XAML(表示)とViewModel(データ)が分かれるため、複雑な表示ロジックがWinFormsのコードビハインド(Form.cs)を汚さない。
  3. レスポンシブな追従: WinForms側のElementHostAnchorを上下左右に設定するだけで、フォームのリサイズに完璧に追従します。

「WinFormsは古い」と諦める前に、ElementHostという架け橋を使って、WPFの強力な表現力を取り入れてみてはいかがでしょうか。

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?