自动调整 DataGrid 大小






4.43/5 (13投票s)
2003 年 11 月 13 日
4分钟阅读

257983

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,名字有什么关系! 这个类将执行以下操作
- 看起来很漂亮,默认样式不行。
- 检测 DataGrid 的 DataSource 中的更改。
- 检测 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 项目所示,它并不总是优雅的。