2021.1.8

DataGridの特定の列幅を可変で表示する(水平スクロールバー有り)

DataGridで一覧を表示する際、特定の列幅のみ可変で、水平スクロールバー有りで表示したいといったことがあったので、その方法についてです。

コード

以下は、DataGridの3列目を可変にした場合のコードになります。

◆MainWindow.xaml


<Window x:Class="WpfApp1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        mc:Ignorable="d"
        Title="MainWindow" Height="400" Width="600">
    <Canvas>
        <Button Name="Button01" Canvas.Top="5" Canvas.Left="10" Content="表示" Padding="10, 2" Width="50" Click="Button01_Click"/>
        <Button Name="Button02" Canvas.Top="5" Canvas.Left="70" Content="クリア" Padding="10, 2" Width="50" Click="Button02_Click"/>
        <DataGrid Name="DataGrid01" Canvas.Top="40" Canvas.Left="10" Width="564" Height="300"
                  AutoGenerateColumns="False" CanUserAddRows="False" AlternatingRowBackground="#f8f8f8"
                  HeadersVisibility="Column" GridLinesVisibility="None">
            <DataGrid.Columns>
                <DataGridTextColumn Header="商品名" Binding="{Binding Name}" Width="200"/>
                <DataGridTextColumn Header="金額" Binding="{Binding Price}" Width="100"/>
                <DataGridTextColumn Header="備考" Binding="{Binding Description}" MinWidth="238" Width="auto"/>
            </DataGrid.Columns>
        </DataGrid>
    </Canvas>
</Window>

MinWidthに最小の列幅を設定し、Width="auto"とすることで、セルの内容によって表示時に列幅が自動で調整され、DataGridの幅を超える場合、水平スクロールバーが表示されるようになります。「HeadersVisibility="Column"」と「GridLinesVisibility="None"」については見栄えのための設定です。

◆MainWindow.cs


using System;
using System.Linq;
using System.Windows;
using System.Windows.Controls;

namespace WpfApp1
{
    public partial class MainWindow : Window
    {
        private int count = 0;

        public MainWindow()
        {
            InitializeComponent();
        }

        private void Button01_Click(object sender, EventArgs e)
        {
            var items = Enumerable.Range(1, 20)
                .Select(x => new Product { Name = $"商品{x:00}", Price = 100, Description = "備考" })
                .ToList();

            count++;
            if(count % 2 == 0)
            {
                items[0].Description = "123456789012345678901234567890";
            }

            DataGrid01.ItemsSource = items;

            // 列幅のリセット
            DataGrid01.Columns[2].Width = DataGrid01.Columns[2].MinWidth;
            DataGrid01.Columns[2].Width = DataGridLength.Auto;

            // スクロール位置のリセット(垂直、水平)
            DataGrid01.ScrollIntoView(DataGrid01.Items[0], DataGrid01.Columns[0]);
        }

        private void Button02_Click(object sender, EventArgs e)
        {
            DataGrid01.ItemsSource = null;
        }
    }

    public class Product
    {
        public string Name { get; set; }
        public int Price { get; set; }
        public string Description { get; set; }
    }
}

動作確認のため、表示ボタンを押すたびに表示するデータの内容を書き換えています。

また、再表示の際に、そのままでは前回の水平スクロールがそのまま残ってしまうので、データセット後に列幅のリセットを行っています。

実行結果

上記のコードを実行すると以下のような挙動になります。

◆起動時

◆1回目

◆2回目

◆3回目

実際にやってみて分かったのですが、MinWidthをギリギリの幅に設定してしまうと、なぜか、再表示で枠内に収まっているにも関わらず、水平スクロールバーが表示されてしまうことがあったので、可能なら水平スクロールバーは表示ない形で実装した方が、後々の不具合はないかもしれません。(上記のコードではMinWidthに余裕を持った幅を設定しています)

WPF】関連記事