为什么列.Insert不更新DataGridView(C#)中的DisplayIndex

本文关键字:中的 DisplayIndex DataGridView Insert 更新 为什么 | 更新日期: 2023-09-27 17:48:52

我以编程方式在DataGridView中插入一列(即,不绑定到任何数据表/数据库),如下所示:

int lastIndex = m_DGV.Columns.Count - 1;  // Count = 4 in this case
DataGridViewTextBoxColumn col = (DataGridViewTextBoxColumn)m_DGV.Columns[lastIndex];
m_DGV.Columns.RemoveAt(lastIndex);
m_DGV.Columns.Insert(insertIndex, col);  // insertIndex = 2

我发现使用这种方法时,我的列在视觉上会出现混乱。解决方法是在之后手动设置列的DisplayIndex属性。添加这段代码"修复了它",但我不明白它为什么会这样。

Console.Write(m_DGV.Columns[0].DisplayIndex); // Has value of 0
Console.Write(m_DGV.Columns[1].DisplayIndex); // Has value of 1
Console.Write(m_DGV.Columns[2].DisplayIndex); // Has value of 3
Console.Write(m_DGV.Columns[3].DisplayIndex); // Has value of 2
col.DisplayIndex = insertIndex;
Console.Write(m_DGV.Columns[0].DisplayIndex); // Has value of 0
Console.Write(m_DGV.Columns[1].DisplayIndex); // Has value of 1
Console.Write(m_DGV.Columns[2].DisplayIndex); // Has value of 2
Console.Write(m_DGV.Columns[3].DisplayIndex); // Has value of 3

顺便说一句,我的网格可以动态地增加它的列数。我想把它分成块,这样每次插入都不需要列分配(以及相关的初始化)。然后,通过从末尾抓取一个未使用的列,将其插入所需位置,并使其可见,来添加每个"新"列。

为什么列.Insert不更新DataGridView(C#)中的DisplayIndex

我怀疑这是因为DataGridView中列的顺序不一定决定显示顺序,尽管默认情况下没有明确指定列的顺序决定DisplayIndex属性值。这就是为什么有DisplayIndex属性,所以您可以在不执行Inserts的情况下将列添加到集合中——您只需要指定DisplayIndex值,并且对于DisplayIndex等于或大于的所有列都会进行级联更新。从您的示例中可以看出,插入的列也接收到第一个跳过的DisplayIndex值。

从一个问题/答案我发现:

更改DisplayIndex将导致旧之间的所有列DisplayIndex和新的DisplayIndex以进行移位。

与几乎所有集合(LinkedLists除外)一样,添加到集合中总是比插入到集合中更好。你所看到的行为就是这条规则的反映。

我有几个想法。

  1. 不如用唯一的名称而不是集合中的索引来寻址列?他们可能还没有名字,但如果你给他们起一个有意义的名字,你就可以知道谁是谁。

  2. 可以使用DataGridViewColumnCollection类的GetFirstColumnGetNextColumnGetPreviousColumnGetLastColumn方法,这些方法按显示顺序工作,而不是按集合中的顺序工作。您也可以使用for循环和m_DGV.Columns[i]遍历集合,直到找到所需的集合。

  3. 创建继承的DataGridViewDataGridViewColumnCollectionDataGridView只是被重写以使用新的集合类。新的DataGridViewColumnCollection将包含一个通过显示索引来寻址集合的方法,大概是通过遍历集合直到找到所需的集合(请参见#2)。或者,您可以保存一个字典,并针对大量列保持更新。

    我怀疑保留字典是否能提高性能,因为每次列移动时,基本上都必须重写整个内容。无论如何,遍历都是O(n),除非您谈论的是具有数百列的异步操作,否则您可能还可以。

    您也可以覆盖this[]操作符,假设它不会破坏DataGridView

想法#1可能是最容易实现的,但不一定是最漂亮的。想法#2有效,您可以将其放入函数DataGridViewColumn GetColumnByDisplayIndex(int Index)中。第三个想法很可爱,当然也是最概括的方法,但也并非微不足道。

感谢cfeduke的出色建议。我怀疑Insert会更慢,但提供的链接启发了我到底慢了多少。

这就提出了如何在DataGridView上有效地动态插入和删除列的问题。看起来理想的设计是使用AddAddRange添加大量列,然后永远不要真正删除它们。然后,您可以通过将Visible属性设置为false来模拟删除。您可以通过抓取一个不可见的列来插入一列,设置其DisplayIndex并使其可见。

然而,我怀疑这种做法会有地雷需要避免。最重要的是,您不能再以简单的方式对数据进行索引。也就是说,m_DGV.Columns[i]m_DGV.Rows[n].Cells[i]将不会被正确地映射。我想您可以创建一个Map/Dictionary来维护外部直观映射。

由于我的应用程序(按照目前的设计)需要频繁地插入和删除列,这可能是值得的。有人有什么建议吗?