C#: DataGridView 在右侧和滚动条上的额外 space

C#: DataGridView's extra space on right-hand side and scrollbar

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

  1. DataGridView 需要显示没有水平滚动条的所有列,除非它影响任何单元格内容的可读性。如果它开始隐藏单元格内容,则需要出现水平滚动条。
  2. 无论当前显示多少列,也无论是否显示水平滚动条,DataGridView的数据右侧必须填充,因此没有未使用的space.
  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。通过缩小一些列宽,它在右侧创建了额外的 space,这违反了要求 #2.

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

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

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

这些要求对我来说似乎有些晦涩难懂。一个问题是要求 3…

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

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

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

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

假设以上是正确的,另一个要求

”2。无论当前显示多少列,也无论是否显示水平滚动条,DataGridView 的数据右侧必须填充,因此没有未使用的space。”

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

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

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

全局变量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;
  }
}