65.9K
CodeProject 正在变化。 阅读更多。
Home

自动调整 DataGrid 大小

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.43/5 (13投票s)

2003 年 11 月 13 日

4分钟阅读

viewsIcon

257983

downloadIcon

3984

一个能够调整其最后一列大小的 DataGrid。

引言

我用 C# 构建的大多数项目要么是基于控制台的,要么是类库。 最近我也一直在构建一些图形应用程序。 我在使用 Java - Swing 界面构建图形应用程序方面有一些经验,所以我希望过渡到 C# 会很容易。 我在 Java 中发现的一个非常有趣的事情是布局管理器的使用,以及在表单上自定义控件视图的强大能力。

C# 不使用任何布局管理器,而是依赖绝对定位。 Java 中也提供了此“功能”,但当然不受欢迎,对我来说,使用布局管理器效果更好。 此外,Java 的第二个优势——可定制性——也是我在 .NET 中所缺少的。 在 Java 中容易实现的一些东西在 C# 中要困难得多。 在本文中,我将展示如何围绕一个特定 Windows Forms 控件(DataGrid)的一个很小的问题构建。

我发现 DataGrid 组件缺少一些我迫切需要的属性。 这里要解决的问题是最后一列的大小。 当要显示的表格大小小于 DataGrid 的 ClientSize 时,最后一列将不会调整大小以适应整个区域。 下图显示了这个问题。

红色箭头“A”指向我想要处理的区域。 我希望网格自动调整其最后一列的大小,或者所有列都稍微调整一下,以便 DataGrid 填满指定的空间。 这可以做到,但并不完全优雅。 目前我的实现仅适用于 DataTable 作为 DataSource,但是移植应该很容易。 现在开始实际工作..

代码

经过一番搜索,我发现解决这个问题的最佳方法是构建一个自定义的 DataGridTableStyle。 我将它命名为 AutoResizeDataGridTableStyle,名字有什么关系! 这个类将执行以下操作

  1. 看起来很漂亮,默认样式不行。
  2. 检测 DataGrid 的 DataSource 中的更改。
  3. 检测 DataGrid 的 Size 中的更改。

实现这一点并不难,可以使用 DataGrid 发出的事件来检测更改。 这将使 AutoResizeDataGridTableStyle 有点难看,因为我们需要注册事件。 这意味着我们不能只将 AutoResizeDataGridTableStyle 的默认实例添加到 DataGrid 的 TableStyles 集合中。

看起来很漂亮

创建 DataGridTableStyle 的主要原因是使 DataGrid 看起来不错。 我们将在构造函数中添加一些美感。 变量 OFFSET_GRID 将在后面解释。

public class AutoResizeDataGridTableStyle: DataGridTableStyle
{
    private int OFFSET_GRID = 39;

    public AutoResizeDataGridTableStyle(): base()
    {
        BackColor = Color.WhiteSmoke;
        AlternatingBackColor = Color.Lavender;
        ForeColor = Color.MidnightBlue;
        GridLineColor = Color.Gainsboro;
        HeaderBackColor = Color.MidnightBlue;
        HeaderForeColor = Color.WhiteSmoke;
        LinkColor = Color.Teal;
        SelectionBackColor = Color.CadetBlue;
        SelectionForeColor = Color.WhiteSmoke;
        ColumnHeadersVisible = true;
        RowHeadersVisible = true;
        HeaderFont = new Font("Microsoft Sans Serif", 8);
    }

OnDataSourceChanged

我们需要检测 DataGrid 的 DataSource 中的更改,以便能够将 DataGridColumnStyles 添加到 DataGridTableStyle。 该类不支持对这些样式进行任何高级处理,它只是构建普通的 DataGridTextBoxColumns。 正如你所看到的,这个方法只适用于 DataTable。 如果这一切对你来说都是胡言乱语,请阅读关于 DataGrid 的手册,它不是最好的,但它是一个开始。

public void OnDataSourceChanged(object sender, EventArgs e)
{
    GridColumnStyles.Clear();
    if(DataGrid != null && DataGrid.DataSource != null &&
        DataGrid.DataSource is DataTable)
    {
        DataTable currentTable = (DataTable)DataGrid.DataSource;
        foreach(DataColumn column in currentTable.Columns)
        {
            DataGridColumnStyle style = new DataGridTextBoxColumn();
            style.HeaderText = column.ColumnName;
            style.MappingName = column.ColumnName;
            GridColumnStyles.Add(style);
        }
    }
    // Call the eventhandler for resize events
    OnDataGridResize(this,new EventArgs());
}

该方法只是遍历 DataTable 中的每一列,为其创建一个新的 DataGridTextBoxColumn,最后调整 DataGrid 的列的大小。

OnDataGridResize

当 DataGrid 更改其 Size 时,实际的列应该随着 DataGrid 调整大小。 这是通过监听 DataGrid 的 Resize 事件来实现的。 当网格调整大小时,我们将计算总列宽并验证它与 DataGrid 的 ClientSize 的差异。

这就是主要问题出现的地方。 计算总列宽是可能的,但您可能已经注意到上图中第二个箭头 (B),它指向第一个列之前,一个你无法以任何我所知道的方式访问的列,一个有宽度的列! 这将使正确计算整个表格宽度几乎不可能。 我们可以做一个有根据的猜测,但屏幕分辨率会使这有点棘手。 这是一个有根据的猜测,它被称为 OFFSET_GRID。 我实际上已经在我的显示器上用不同的分辨率测试过这个,对我来说,这个值总是一样的。 对你来说呢? 我不知道,可能不是!

首先,计算总网格宽度的方法

private int GetGridColumnWidth()
{
    // No columns, return error
    if(GridColumnStyles.Count == 0)
        return -1;
    // Easy 1
    int width = 0;
    foreach(DataGridColumnStyle columnStyle in GridColumnStyles)
    {
        width += columnStyle.Width;
    }

    return width + OFFSET_GRID;
}

接下来是处理调整大小事件的方法

public void OnDataGridResize(object sender, EventArgs e)
{
    // Parent?
    if(DataGrid != null)
    {
        // Get column width
        int columnWidth;
        if( (columnWidth = GetGridColumnWidth()) != -1)
        {
            // Get the client width
            int clientWidth = DataGrid.ClientSize.Width;
            // Are there columns? redundant check
            if(GridColumnStyles.Count > 0)
            {
                // whats the newWidth
                int newWidth = 
                    GridColumnStyles [GridColumnStyles.Count - 1].Width +
                    clientWidth - columnWidth;
                // is the new width valid?
                if(newWidth > PreferredColumnWidth)
                    GridColumnStyles[GridColumnStyles.Count - 1].Width = 
                                                                   newWidth;
                else
                    GridColumnStyles[GridColumnStyles.Count - 1].Width = 
                                                        PreferredColumnWidth;
            }
        }
        // Redraw
        DataGrid.Invalidate(true);
    }
}

调用它

现在我们几乎快要结束这篇文章了,最后我将展示如何将这个类连接到 DataGrid 中,只需要几行代码。

DataGrid gridView = new DataGrid();
AutoResizeDataGridTableStyle style = new AutoResizeDataGridTableStyle();
gridView.DataSourceChanged += new EventHandler(style.OnDataSourceChanged);
gridView.Resize += new EventHandler(style.OnDataGridResize);
style.MappingName = "MyTable";
gridView.TableStyles.Add(style);

结论

在使用 C# 构建 WinForms 应用程序后,我很遗憾地说我更喜欢 Java。 我使用的类缺少我希望看到的那种可定制程度。 有可用的解决方法,但正如 OFFSET_GRID 项目所示,它并不总是优雅的。

© . All rights reserved.