【问题标题】:C#: DataGridView's extra space on right-hand side and scrollbarC#:DataGridView 在右侧和滚动条上的额外空间
【发布时间】:2017-10-16 19:04:56
【问题描述】:

我有一个DataGridView 控件,列数每 10 分钟根据用户的输入而变化。 需要实现的是:

  1. DataGridView 需要显示没有水平滚动条的所有列,除非它影响任何单元格内容的可读性。如果它开始隐藏单元格内容,则需要出现水平滚动条。
  2. 无论当前显示多少列,无论是否显示水平滚动条,DataGridView 数据的右侧都必须填充,以免出现未使用的空间。
  3. 无论单元格内容的长度如何,所有的列宽都需要相同。 (一个单元格可以有一个从 10 到 9999 的整数)

需要同时满足所有这 3 个要求,但如果我尝试满足一个要求,其他要求就会崩溃。我确信无论如何总是至少有 16 列。是否会有更多列完全取决于用户。

谁能告诉我以下有什么问题?

int countVisible = 0; //Count the number of columns displayed
foreach(DataGridViewColumn col in myDGV.Columns)
    if(col.Visible) countVisible++;

//By default, use Fill mode
DataGridViewAutoSizeColumnMode mode = DataGridViewAutoSizeColumnMode.Fill;

//I am trying to show up to 20 columns without a scrollbar
//A horizontal scrollbar required for more than 20 columns
//If there are more than 20 columns, use DisplayedCells mode
if(countVisible > 20)
    mode = DataGridViewAutoSizeColumnMode.DisplayedCells;

//Apply the mode to all columns
for(int i = 0; i < myDGV.Columns.Count; i++)
    myDGV.Columns[i].AutoSizeMode = mode;  

如果列数小于某个值,此代码有效,但在大于某个值的情况下,它会缩小所有行中只有 2 位数字的列的宽度,它违反了要求#3。通过缩小一些列宽,它会在右侧创建额外的空间,这违反了要求 #2。

我迷路了,被困住了。有人可以帮忙吗?任何建议将不胜感激。

【问题讨论】:

标签: c# datagridview width


【解决方案1】:

这些要求对我来说似乎有些模糊。一个问题是要求 3……

”3.无论单元格内容的长度如何,所有列宽都需要相同。 (一个单元格可以有一个从 10 到 9999 的整数)” ...

如果所有列的宽度必须相同,并且至少一 (1) 个单元格的值是“9999”,那么所有列都将是这个宽度,不管它有多少位数。

似乎要求将所有数据显示在一个单元格中,此外……所有列的宽度都相同。这将需要遍历每个单元格并找到具有最大宽度的单元格以显示其所有数据,并使所有列都具有此宽度以保持之前的要求。

关键是,要求所有列的大小相同并确保显示每个单元格的所有内容几乎没有问题……每一列都必须是最大值的宽度。任何其他情况都会违反其中一项要求。

假设以上正确,其他要求

”2.无论当前显示多少列,无论是否显示水平滚动条,DataGridView 的数据右侧都必须被填充,以确保没有未使用的空间。” ...

我相信您将不得不控制这一点。不幸的是,网格列的“填充”属性很乐意将一百列塞进一个小空间。这表明您必须获取网格显示的宽度,计算有多少列,找到列的宽度并检查它是否适合网格显示。

这意味着列宽的最小值。如果每列宽度设置为最小值并且所有列的总宽度大于网格宽度,那么显然您将需要一个水平滚动条。

鉴于此,找到所有列的总宽度很容易。如果此值大于网格宽度,则水平滚动条将自动出现,除非您想避免可能涉及调整网格大小的列的可能拆分,否则无需执行任何其他操作。如果列的总宽度小于网格宽度……那么只需将列设置为填充。下面是一个例子。

全局变量minWidth 用于确保所有列都至少是这个值。这是您可以通过其他方式获得的值;在这种情况下,它的目的是设置列的最小宽度。

首先,检查宽度是否小于最小值,如果是,则将其设置为最小值。接下来,将每列宽度设置为给定值。最后检查所有列的总宽度是否大于网格宽度。如果列不适合网格宽度,则只需将网格设置为DisplayedCells,水平滚动条就会弹出。 .如果列适合,则只需将网格AutoColumnSizeMode 设置为Fill。希望这会有所帮助。

int minWidth = 40;

private int YourMethodToGetColumnWidth() {
  return myDGV.Width / myDGV.Columns.Count;
}

private void SetColumnWidths() {
  int columnWidth = YourMethodToGetColumnWidth();
  if (columnWidth < minWidth)
    columnWidth = minWidth;
  foreach (DataGridViewColumn col in myDGV.Columns)
    col.Width = columnWidth;
  int allColumnsWidth = columnWidth * myDGV.Columns.Count;
  if (allColumnsWidth > myDGV.Width) {
    myDGV.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.DisplayedCells;
  }
  else {
    myDGV.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.Fill;
  }
}

【讨论】:

  • 谢谢!能够解决问题!你是个天才。
【解决方案2】:

我昨天读到了你有趣的问题。想一想,在我看来,最好的解决方案是完全摆脱 AutoSizeMode 并为列的最小宽度创建一个变量 ColMinWidth。然后获取 DataGridView.Width 并将其除以所需的列数(稍作调整,可能少 2px)。如果计算出的列宽度大于 ColMinWidth,那么这将是列的宽度,否则使用 ColMinWidth。 最后将该宽度设置为所有列。

我认为这是最小的解决方案,与带有隐藏捕获的 AutoSize 不同,可靠。

【讨论】: