Windows フォーム DataGridView コントロールの列フィル モード

列フィル モードでは、DataGridView コントロールの列は、コントロールの表示領域の幅を満たすように自動的にサイズ変更されます。 すべての列の幅を MinimumWidth プロパティの値以上にするために水平スクロール バーが必要な場合を除き、コントロールに水平スクロール バーは表示されません。

各列のサイズ変更動作は、InheritedAutoSizeMode プロパティによって異なります。 このプロパティの値は、列の AutoSizeMode プロパティから継承されるか、または列の値が既定値の NotSet である場合はコントロールの AutoSizeColumnsMode プロパティから継承されます。

列ごとに異なるサイズ変更モードを使用できます。ただし、サイズ変更モードが Fill であるすべての列は、それ以外の列が使用していない表示領域を共有します。 この領域の幅は、フィル モードの列の間で、それぞれの FillWeight プロパティの値の比率に基づいて分割されます。 たとえば、FillWeight の値が 100 の列と 200 の列がある場合、最初の列はもう 1 つの列の半分の幅になります。

フィル モードでのユーザーによるサイズ変更

セルの内容に基づいてサイズが変更されるモードとは異なり、フィル モードでは、ユーザーは Resizable プロパティの値が true の列のサイズを変更できます。 ユーザーが 1 つのフィル モード列のサイズを変更すると、サイズ変更した列より後のすべてのフィル モード列 (RightToLeftfalse の場合は右側の列、それ以外の場合は左側の列) のサイズも、表示に使用できる幅の変化とつりあうように変わります。 サイズ変更した列より後にフィル モード列がない場合は、コントロール内の他のすべてのフィル モード列のサイズが変更されます。 コントロール内に他のフィル モード列がない場合は、サイズ変更は無視されます。 フィル モードでない列のサイズを変更した場合は、コントロール内のすべてのフィル モード列のサイズが、変更とつりあうように変わります。

1 つのフィル モード列のサイズを変更すると、それに合わせて変更されたすべての列の FillWeight の値が比率に応じて調整されます。 たとえば、FillWeight 値が 100 である 4 つのフィル モード列のうち、2 番目の列の幅を元の幅の半分にすると、各フィル モード列の FillWeight 値はそれぞれ 100、50、125、125 になります。 フィル モードでない列のサイズを変更しても、フィル モード列のサイズは同じ比率を維持するように変更されるだけなので、FillWeight 値は変わりません。

内容に基づく FillWeight の調整

フィル モード列の FillWeight の値は、DataGridView の自動サイズ変更メソッドを使用して初期化できます。たとえば、AutoResizeColumns メソッドがあります。 このメソッドは、まず、列の内容を表示するのに必要な幅を計算します。 次に、計算した幅の比率に一致するように、すべてのフィル モード列の FillWeight の値がコントロールによって調整されます。 最後に、この新しい FillWeight の比率を使用して、コントロール内のすべての列が水平方向に使用可能な領域を満たすようにフィル モード列のサイズがコントロールによって変更されます。

説明

AutoSizeModeMinimumWidthFillWeight、および Resizable の各プロパティに適切な値を使用すると、さまざまなシナリオに応じて列のサイズ変更動作をカスタマイズできます。

次のデモ コードでは、AutoSizeModeFillWeight、および MinimumWidth の各プロパティのさまざまな値をさまざまな列で試すことができます。 この例では、DataGridView コントロールはそれ自体の Columns コレクションにバインドしており、それぞれの列は HeaderTextAutoSizeModeFillWeightMinimumWidth、および Width の各プロパティにバインドしています。 各列はコントロール内の行でも表されており、1 つの行で値を変更すると対応する列のプロパティも更新されるので、値の相互作用を確認できます。

コード

using System;
using System.ComponentModel;
using System.Reflection;
using System.Windows.Forms;

public class Form1 : Form
{
    [STAThread]
    public static void Main()
    {
        Application.Run(new Form1());
    }

    private DataGridView dataGridView1 = new DataGridView();

    public Form1()
    {
        dataGridView1.Dock = DockStyle.Fill;
        Controls.Add(dataGridView1);
        InitializeDataGridView();
        Width *= 2;
        Text = "Column Fill-Mode Demo";
    }

    private void InitializeDataGridView()
    {
        // Add columns to the DataGridView, binding them to the
        // specified DataGridViewColumn properties.
        AddReadOnlyColumn("HeaderText", "Column");
        AddColumn("AutoSizeMode");
        AddColumn("FillWeight");
        AddColumn("MinimumWidth");
        AddColumn("Width");

        // Bind the DataGridView to its own Columns collection.
        dataGridView1.AutoGenerateColumns = false;
        dataGridView1.DataSource = dataGridView1.Columns;

        // Configure the DataGridView so that users can manually change
        // only the column widths, which are set to fill mode.
        dataGridView1.AllowUserToAddRows = false;
        dataGridView1.AllowUserToDeleteRows = false;
        dataGridView1.AllowUserToResizeRows = false;
        dataGridView1.RowHeadersWidthSizeMode =
            DataGridViewRowHeadersWidthSizeMode.DisableResizing;
        dataGridView1.ColumnHeadersHeightSizeMode =
            DataGridViewColumnHeadersHeightSizeMode.DisableResizing;
        dataGridView1.AutoSizeColumnsMode =
            DataGridViewAutoSizeColumnsMode.Fill;

        // Configure the top left header cell as a reset button.
        dataGridView1.TopLeftHeaderCell.Value = "reset";
        dataGridView1.TopLeftHeaderCell.Style.ForeColor =
            System.Drawing.Color.Blue;

        // Add handlers to DataGridView events.
        dataGridView1.CellClick +=
            new DataGridViewCellEventHandler(dataGridView1_CellClick);
        dataGridView1.ColumnWidthChanged += new
            DataGridViewColumnEventHandler(dataGridView1_ColumnWidthChanged);
        dataGridView1.CurrentCellDirtyStateChanged +=
            new EventHandler(dataGridView1_CurrentCellDirtyStateChanged);
        dataGridView1.DataError +=
            new DataGridViewDataErrorEventHandler(dataGridView1_DataError);
        dataGridView1.CellEndEdit +=
            new DataGridViewCellEventHandler(dataGridView1_CellEndEdit);
        dataGridView1.CellValueChanged +=
            new DataGridViewCellEventHandler(dataGridView1_CellValueChanged);
    }

    private void AddReadOnlyColumn(String dataPropertyName, String columnName)
    {
        AddColumn(typeof(DataGridViewColumn), dataPropertyName, true,
            columnName);
    }

    private void AddColumn(String dataPropertyName)
    {
        AddColumn(typeof(DataGridViewColumn), dataPropertyName, false,
            dataPropertyName);
    }

    // Adds a column to the DataGridView control, binding it to specified
    // property of the specified type and optionally making it read-only.
    private void AddColumn(
        Type type,
        String dataPropertyName,
        Boolean readOnly,
        String columnName)
    {
        // Retrieve information about the property through reflection.
        PropertyInfo property = type.GetProperty(dataPropertyName);

        // Confirm that the property exists and is accessible.
        if (property == null) throw new ArgumentException("No accessible " +
            dataPropertyName + " property was found in the " + type.Name + " type.");

        // Confirm that the property is browsable.
        BrowsableAttribute[] browsables = (BrowsableAttribute[])
            property.GetCustomAttributes(typeof(BrowsableAttribute), false);
        if (browsables.Length > 0 && !browsables[0].Browsable)
        {
            throw new ArgumentException("The " + dataPropertyName + " property has a " +
            "Browsable(false) attribute, and therefore cannot be bound.");
        }

        // Create and initialize a column, using a combo box column for
        // enumeration properties, a check box column for Boolean properties,
        // and a text box column otherwise.
        DataGridViewColumn column;
        Type valueType = property.PropertyType;
        if (valueType.IsEnum)
        {
            column = new DataGridViewComboBoxColumn();

            // Populate the drop-down list with the enumeration values.
            ((DataGridViewComboBoxColumn)column).DataSource
                = Enum.GetValues(valueType);
        }
        else if (valueType.Equals(typeof(Boolean)))
        {
            column = new DataGridViewCheckBoxColumn();
        }
        else
        {
            column = new DataGridViewTextBoxColumn();
        }

        // Initialize and bind the column.
        column.ValueType = valueType;
        column.Name = columnName;
        column.DataPropertyName = dataPropertyName;
        column.ReadOnly = readOnly;

        // Add the column to the control.
        dataGridView1.Columns.Add(column);
    }

    private void ResetDataGridView()
    {
        dataGridView1.CancelEdit();
        dataGridView1.Columns.Clear();
        dataGridView1.DataSource = null;
        InitializeDataGridView();
    }

    private void dataGridView1_CellClick(
        object sender, DataGridViewCellEventArgs e)
    {
        if (e.ColumnIndex == -1 && e.RowIndex == -1)
        {
            ResetDataGridView();
        }
    }

    private void dataGridView1_ColumnWidthChanged(
        object sender, DataGridViewColumnEventArgs e)
    {
        // Invalidate the row corresponding to the column that changed
        // to ensure that the FillWeight and Width entries are updated.
        dataGridView1.InvalidateRow(e.Column.Index);
    }

    private void dataGridView1_CurrentCellDirtyStateChanged(
        object sender, EventArgs e)
    {
        // For combo box and check box cells, commit any value change as soon
        // as it is made rather than waiting for the focus to leave the cell.
        if (!dataGridView1.CurrentCell.OwningColumn.GetType()
            .Equals(typeof(DataGridViewTextBoxColumn)))
        {
            dataGridView1.CommitEdit(DataGridViewDataErrorContexts.Commit);
        }
    }

    private void dataGridView1_DataError(
        object sender, DataGridViewDataErrorEventArgs e)
    {
        if (e.Exception == null) return;

        // If the user-specified value is invalid, cancel the change
        // and display the error icon in the row header.
        if ((e.Context & DataGridViewDataErrorContexts.Commit) != 0 &&
            (typeof(FormatException).IsAssignableFrom(e.Exception.GetType()) ||
            typeof(ArgumentException).IsAssignableFrom(e.Exception.GetType())))
        {
            dataGridView1.Rows[e.RowIndex].ErrorText =
                "The specified value is invalid.";
            e.Cancel = true;
        }
        else
        {
            // Rethrow any exceptions that aren't related to the user input.
            e.ThrowException = true;
        }
    }

    private void dataGridView1_CellEndEdit(
        object sender, DataGridViewCellEventArgs e)
    {
        // Ensure that the error icon in the row header is hidden.
        dataGridView1.Rows[e.RowIndex].ErrorText = "";
    }

    private void dataGridView1_CellValueChanged(
        object sender, DataGridViewCellEventArgs e)
    {
        // Retrieve the property to change.
        String nameOfPropertyToChange =
            dataGridView1.Columns[e.ColumnIndex].Name;
        PropertyInfo propertyToChange =
            typeof(DataGridViewColumn).GetProperty(nameOfPropertyToChange);

        // Retrieve the column to change.
        String nameOfColumnToChange =
            (String)dataGridView1["Column", e.RowIndex].Value;
        DataGridViewColumn columnToChange =
            dataGridView1.Columns[nameOfColumnToChange];

        // Use reflection to update the value of the column property.
        propertyToChange.SetValue(columnToChange,
            dataGridView1[nameOfPropertyToChange, e.RowIndex].Value, null);
    }
}
Imports System.ComponentModel
Imports System.Reflection
Imports System.Windows.Forms

Public Class Form1
    Inherits Form

    <STAThread()> _
    Public Shared Sub Main()
        Application.Run(New Form1())
    End Sub

    Private WithEvents dataGridView1 As New DataGridView()

    Public Sub New()
        dataGridView1.Dock = DockStyle.Fill
        Controls.Add(dataGridView1)
        InitializeDataGridView()
        Width = Width * 2
        Text = "Column Fill-Mode Demo"
    End Sub

    Private Sub InitializeDataGridView()

        ' Add columns to the DataGridView, binding them to the
        ' specified DataGridViewColumn properties.
        AddReadOnlyColumn("HeaderText", "Column")
        AddColumn("AutoSizeMode")
        AddColumn("FillWeight")
        AddColumn("MinimumWidth")
        AddColumn("Width")

        ' Bind the DataGridView to its own Columns collection.
        dataGridView1.AutoGenerateColumns = False
        dataGridView1.DataSource = dataGridView1.Columns

        ' Configure the DataGridView so that users can manually change 
        ' only the column widths, which are set to fill mode. 
        dataGridView1.AllowUserToAddRows = False
        dataGridView1.AllowUserToDeleteRows = False
        dataGridView1.AllowUserToResizeRows = False
        dataGridView1.RowHeadersWidthSizeMode = _
            DataGridViewRowHeadersWidthSizeMode.DisableResizing
        dataGridView1.ColumnHeadersHeightSizeMode = _
            DataGridViewColumnHeadersHeightSizeMode.DisableResizing
        dataGridView1.AutoSizeColumnsMode = _
            DataGridViewAutoSizeColumnsMode.Fill

        ' Configure the top left header cell as a reset button.
        dataGridView1.TopLeftHeaderCell.Value = "reset"
        dataGridView1.TopLeftHeaderCell.Style.ForeColor = _
            System.Drawing.Color.Blue

    End Sub

    Private Sub AddReadOnlyColumn(ByVal dataPropertyName As String, _
        ByVal columnName As String)

        AddColumn(GetType(DataGridViewColumn), dataPropertyName, True, _
            columnName)
    End Sub

    Private Sub AddColumn(ByVal dataPropertyName As String)
        AddColumn(GetType(DataGridViewColumn), dataPropertyName, False, _
            dataPropertyName)
    End Sub

    ' Adds a column to the DataGridView control, binding it to specified 
    ' property of the specified type and optionally making it read-only.
    Private Sub AddColumn( _
        ByVal type As Type, _
        ByVal dataPropertyName As String, _
        ByVal isReadOnly As Boolean, _
        ByVal columnName As String)

        ' Retrieve information about the property through reflection.
        Dim propertyInfo1 As PropertyInfo = type.GetProperty(dataPropertyName)

        ' Confirm that the property exists and is accessible.
        If propertyInfo1 Is Nothing Then
            Throw New ArgumentException("No accessible " & dataPropertyName & _
            " property was found in the " & type.Name & " type.")
        End If

        ' Confirm that the property is browsable.
        Dim browsables As BrowsableAttribute() = CType( _
            propertyInfo1.GetCustomAttributes(GetType(BrowsableAttribute), _
            False), BrowsableAttribute())
        If browsables.Length > 0 AndAlso Not browsables(0).Browsable Then
            Throw New ArgumentException("The " & dataPropertyName & " property has a " & _
            "Browsable(false) attribute, and therefore cannot be bound.")
        End If

        ' Create and initialize a column, using a combo box column for 
        ' enumeration properties, a check box column for Boolean properties,
        ' and a text box column otherwise.
        Dim column As DataGridViewColumn
        Dim valueType As Type = propertyInfo1.PropertyType

        If valueType.IsEnum Then

            column = New DataGridViewComboBoxColumn()

            ' Populate the drop-down list with the enumeration values.
            CType(column, DataGridViewComboBoxColumn).DataSource = _
                [Enum].GetValues(valueType)

        ElseIf valueType.Equals(GetType(Boolean)) Then
            column = New DataGridViewCheckBoxColumn()
        Else
            column = New DataGridViewTextBoxColumn()
        End If

        ' Initialize and bind the column.
        column.ValueType = valueType
        column.Name = columnName
        column.DataPropertyName = dataPropertyName
        column.ReadOnly = isReadOnly

        ' Add the column to the control.
        dataGridView1.Columns.Add(column)

    End Sub

    Private Sub ResetDataGridView()
        dataGridView1.CancelEdit()
        dataGridView1.Columns.Clear()
        dataGridView1.DataSource = Nothing
        InitializeDataGridView()
    End Sub

    Private Sub dataGridView1_CellClick( _
        ByVal sender As Object, ByVal e As DataGridViewCellEventArgs) _
        Handles dataGridView1.CellClick

        If e.ColumnIndex = -1 AndAlso e.RowIndex = -1 Then
            ResetDataGridView()
        End If

    End Sub

    Private Sub dataGridView1_ColumnWidthChanged( _
        ByVal sender As Object, ByVal e As DataGridViewColumnEventArgs) _
        Handles dataGridView1.ColumnWidthChanged

        ' Invalidate the row corresponding to the column that changed
        ' to ensure that the FillWeight and Width entries are updated.
        dataGridView1.InvalidateRow(e.Column.Index)

    End Sub

    Private Sub dataGridView1_CurrentCellDirtyStateChanged( _
        ByVal sender As Object, ByVal e As EventArgs) _
        Handles dataGridView1.CurrentCellDirtyStateChanged

        ' For combo box and check box cells, commit any value change as soon
        ' as it is made rather than waiting for the focus to leave the cell.
        If Not dataGridView1.CurrentCell.OwningColumn.GetType() _
            .Equals(GetType(DataGridViewTextBoxColumn)) Then

            dataGridView1.CommitEdit(DataGridViewDataErrorContexts.Commit)

        End If

    End Sub

    Private Sub dataGridView1_DataError( _
        ByVal sender As Object, ByVal e As DataGridViewDataErrorEventArgs) _
        Handles dataGridView1.DataError

        If e.Exception Is Nothing Then Return

        ' If the user-specified value is invalid, cancel the change 
        ' and display the error icon in the row header.
        If Not (e.Context And DataGridViewDataErrorContexts.Commit) = 0 AndAlso _
            (GetType(FormatException).IsAssignableFrom(e.Exception.GetType()) Or _
            GetType(ArgumentException).IsAssignableFrom(e.Exception.GetType())) Then

            dataGridView1.Rows(e.RowIndex).ErrorText = e.Exception.Message
            e.Cancel = True

        Else
            ' Rethrow any exceptions that aren't related to the user input.
            e.ThrowException = True
        End If

    End Sub

    Private Sub dataGridView1_CellEndEdit( _
        ByVal sender As Object, ByVal e As DataGridViewCellEventArgs) _
        Handles dataGridView1.CellEndEdit

        ' Ensure that the error icon in the row header is hidden.
        dataGridView1.Rows(e.RowIndex).ErrorText = ""

    End Sub

    Private Sub dataGridView1_CellValueChanged( _
        ByVal sender As Object, ByVal e As DataGridViewCellEventArgs) _
        Handles dataGridView1.CellValueChanged

        ' Ignore the change to the top-left header cell.
        If e.ColumnIndex < 0 Then Return

        ' Retrieve the property to change.
        Dim nameOfPropertyToChange As String = _
            dataGridView1.Columns(e.ColumnIndex).Name
        Dim propertyToChange As PropertyInfo = _
            GetType(DataGridViewColumn).GetProperty(nameOfPropertyToChange)

        ' Retrieve the column to change.
        Dim nameOfColumnToChange As String = _
            CStr(dataGridView1("Column", e.RowIndex).Value)
        Dim columnToChange As DataGridViewColumn = _
            dataGridView1.Columns(nameOfColumnToChange)

        ' Use reflection to update the value of the column property. 
        propertyToChange.SetValue(columnToChange, _
            dataGridView1(nameOfPropertyToChange, e.RowIndex).Value, Nothing)

    End Sub

End Class

説明

このデモ アプリケーションは、次のようにして使用します。

  • フォームのサイズを変更します。 FillWeight プロパティの値で示される比率が維持されたまま、列の幅が変わることを確認します。

  • マウスで列の区分線をドラッグして、列のサイズを変更します。 FillWeight 値がどのように変わるかを確認します。

  • 1 つの列の MinimumWidth 値を変更してから、フォームのサイズをドラッグで変更します。 フォームをどれだけ小さくしても Width 値が MinimumWidth 値を下回らないことを確認します。

  • すべての列の MinimumWidth 値を大きくして、その合計値がコントロールの幅を上回るようにします。 水平スクロール バーが表示されることを確認します。

  • 一部の列の AutoSizeMode 値を変更します。 列またはフォームのサイズの変更によって何が起きるかを確認します。

コードのコンパイル

この例で必要な要素は次のとおりです。

  • System、System.Drawing、および System.Windows.Forms の各アセンブリへの参照。

関連項目