Windows 窗体 DataGridView 控件中的列填充模式Column Fill Mode in the Windows Forms DataGridView Control

在列填充模式中,DataGridView 控件自动调整其列的大小,以便它们可填充可用显示区域的宽度。In column fill mode, the DataGridView control resizes its columns automatically so that they fill the width of the available display area. 该控件不显示水平滚动条,除非有必要使每列的宽度等于或大于其 MinimumWidth 属性值。The control does not display the horizontal scroll bar except when it is necessary to keep the width of every column equal to or greater than its MinimumWidth property value.

每列的大小调整行为取决于其 InheritedAutoSizeMode 属性。The sizing behavior of each column depends on its InheritedAutoSizeMode property. 如果列值为 AutoSizeMode(默认值),则此属性的值继承自列的 AutoSizeColumnsMode 属性或控件的 NotSet 属性。The value of this property is inherited from the column's AutoSizeMode property or the control's AutoSizeColumnsMode property if the column value is NotSet (the default value).

每列都可有不同的大小模式,但具有 Fill 大小模式的任何列将共享其他列未使用的显示区域宽度。Each column can have a different size mode, but any columns with a size mode of Fill will share the display-area width that is not used by the other columns. 将根据列的 FillWeight 属性值在填充模式列间按比例划分宽度。This width is divided among the fill-mode columns in proportions relative to their FillWeight property values. 例如,如果两个列的 FillWeight 值为 100 和 200,则第一列的宽度将为第二列的一半。For example, if two columns have FillWeight values of 100 and 200, the first column will be half as wide as the second column.

填充模式中的用户大小调整User Resizing in Fill Mode

不同于基于单元格内容的大小进行调整的调整模式,填充模式不会阻止用户调整 Resizable 属性值为 true 的列。Unlike sizing modes that resize based on cell contents, fill mode does not prevent users from resizing columns that have Resizable property values of true. 当用户调整填充模式列的大小时,也将对已调整列之后的任何填充模式列(如果 RightToLeftfalse,则向右;否则向左)的大小进行调整,以弥补可用宽度的更改。When a user resizes a fill-mode column, any fill-mode columns after the resized column (to the right if RightToLeft is false; otherwise, to the left) are also resized to compensate for the change in the available width. 如果在已调整列之后没有填充模式列,则调整控件中的所有其他填充模式列的大小以进行补偿。If there are no fill-mode columns after the resized column, then all other fill-mode columns in the control are resized to compensate. 如果控件中没有其他的填充模式列,则忽略大小调整。If there are no other fill-mode columns in the control, the resize is ignored. 如果调整了非填充模式的列大小,那么控件中的所有填充模式列都更改大小以便进行补偿。If a column that is not in fill mode is resized, all fill-mode columns in the control change sizes to compensate.

调整填充模式列的大小后,也将按比例调整更改的所有列的 FillWeight 值。After resizing a fill-mode column, the FillWeight values for all columns that changed are adjusted proportionally. 例如,如果四个填充模式列的 FillWeight 值为 100,将第二列的宽度调整为其原始宽度的一半,将导致 FillWeight 值为 100、50、125 和 125。For example, if four fill-mode columns have FillWeight values of 100, resizing the second column to half its original width will result in FillWeight values of 100, 50, 125, and 125. 调整非填充模式中列的大小不会更改任何 FillWeight 值,因为填充模式列只需在保留相同比例的情况下调整大小以进行补偿。Resizing a column that is not in fill mode will not change any FillWeight values because the fill-mode columns will simply resize to compensate while retaining the same proportions.

基于内容的 FillWeight 调整Content-Based FillWeight Adjustment

可以使用 FillWeight 自动调整大小的方法(如 DataGridView 方法)初始化填充模式列的 AutoResizeColumns 值。You can initialize FillWeight values for fill-mode columns by using the DataGridView automatic resizing methods, such as the AutoResizeColumns method. 此方法首先计算列所需的宽度以显示其内容。This method first calculates the widths required by columns to display their contents. 接下来,该控件调整所有填充模式列的 FillWeight 值,以便其比例匹配计算的宽度的比例。Next, the control adjusts the FillWeight values for all fill-mode columns so that their proportions match the proportions of the calculated widths. 最后,该控件使用新的 FillWeight 比例调整填充模式列的大小,以便控件中的所有列都填充可用的水平空间。Finally, the control resizes the fill-mode columns using the new FillWeight proportions so that all columns in the control fill the available horizontal space.

示例Example

说明Description

通过使用 AutoSizeModeMinimumWidthFillWeightResizable 属性的适当值,可为多种不同方案自定义列的大小调整行为。By using appropriate values for the AutoSizeMode, MinimumWidth, FillWeight, and Resizable properties, you can customize the column-sizing behaviors for many different scenarios.

下面的演示代码使你能够试验不同列的 AutoSizeModeFillWeightMinimumWidth 属性的不同值。The following demonstration code enables you to experiment with different values for the AutoSizeMode, FillWeight, and MinimumWidth properties of different columns. 在此示例中,DataGridView 控件绑定到其自身的 Columns 集合,并且有一列绑定到 HeaderTextAutoSizeModeFillWeightMinimumWidthWidth 各属性。In this example, a DataGridView control is bound to its own Columns collection, and one column is bound to each of the HeaderText, AutoSizeMode, FillWeight, MinimumWidth, and Width properties. 每列也可由控件中的行表示,更改行的值将更新对应列的属性,这样你可以看到值如何进行交互。Each of the columns is also represented by a row in the control, and changing values in a row will update the properties of the corresponding column so that you can see how the values interact.

代码Code

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

CommentsComments

使用此演示应用程序:To use this demonstration application:

  • 更改窗体大小。Change the size of the form. 观察列如何更改宽度并同时保留由 FillWeight 属性值指示的比例。Observe how columns change their widths while retaining the proportions indicated by the FillWeight property values.

  • 通过使用鼠标拖动列分隔线,更改列的大小。Change the column sizes by dragging the column dividers with the mouse. 观察 FillWeight 值如何进行更改。Observe how the FillWeight values change.

  • 更改某一列的 MinimumWidth 值,然后拖动以调整窗体大小。Change the MinimumWidth value for one column, then drag to resize the form. 当将窗体调整到足够小时,观察如何让 Width 值不低于 MinimumWidth 值。Observe how, when you make the form small enough, the Width values do not go below the MinimumWidth values.

  • 将所有列的 MinimumWidth 值变大,以便组合值超过控件的宽度。Change the MinimumWidth values for all columns to large numbers so that the combined values exceed the width of the control. 观察水平滚动条的显示方式。Observe how the horizontal scroll bar appears.

  • 更改某些列的 AutoSizeMode 值。Change the AutoSizeMode values for some columns. 当调整列或窗体的大小时,观察效果。Observe the effect when you resize columns or the form.

编译代码Compiling the Code

此示例需要:This example requires:

  • 对 System、System.Drawing 和 System.Windows.Forms 程序集的引用。References to the System, System.Drawing, and System.Windows.Forms assemblies.

另请参阅See also