在Windows窗体DataGridView的手风琴

我需要在Windows窗体DataGridView中实现某种手风琴效果。 当用户select一行时,行被展开显示更多的信息,如果可能的话还有一些button或其他控件。 问题是,我完全没有线索,如何做到这一点。 我试图search网页,但是我没有发现任何可以使我在正确的方向创造这个。 我希望有人能告诉我如何做到这一点? (不一定是代码示例)

我创build了下面的模型来显示我想要做的事情。

我想过调整列高度并重写OnPaint方法。 我只需要在第一个版本中显示一些文本。 如果这可能会很好。 我知道,将来我需要放置一些button或其他控件来完成与所选项目的各种事情。 如果这样做很复杂的话,我现在就会跳过这个部分。 我知道我可以使用工具提示的文本和button列等,但在我的情况下,我需要做一个手风琴。

DataGridView与手风琴样机

最好的问候Hans Milling …

这并不是很难做到。 最好的方法是创建一个专用的UserControl并将其覆盖在正确的位置。

为了腾出空间,只需更改行的Height ,跟踪行,这样就可以在选择失败时恢复。

您还必须决定是否可以扩展多行,以及用户应该如何扩展和重置行。

UserControl可以有一个函数displayRowData(DataGridViewRow row) ,你可以调用显示你感兴趣的字段在其Labels等。

你也应该有一个关于Buttons如何与DataGridView交互的计划。

如果您只想一行扩展一行,则可以预先创建UC ,将DGV作为Parent并将其隐藏。 稍后用户交互,如点击行或某个单元格,您将它移动到右边的行并显示它。

如果不止一行可以扩展,您将需要创建几个UCs并跟踪它们在List

这是一个鼓励你的最小例子..:

在这里输入图像说明

 int normalRowHeight = -1; UcRowDisplay display = new UcRowDisplay(); DataGridViewRow selectedRow = null; public Form1() { InitializeComponent(); // create one display object display = new UcRowDisplay(); display.Visible = false; display.Parent = DGV; display.button1Action = someAction; } 

在您填装了DGV之后

  // store the normal row height normalRowHeight = DGV.Rows[0].Height; 

你至少需要这些事件:

 private void DGV_SelectionChanged(object sender, EventArgs e) { if (selectedRow != null) selectedRow.Height = normalRowHeight; if (DGV.SelectedRows.Count <= 0) { selectedRow = null; display.Hide(); return; } // assuming multiselect = false selectedRow = DGV.SelectedRows[0]; // assuming ColumnHeader show with the same height as the rows int y = (selectedRow.Index + 1) * normalRowHeight; display.Location = new Point(1, y); // filling out the whole width of the DGV. // maybe you need more, if the DGV is scrolling horizontally // or less if you show a vertical scrollbar.. display.Width = DGV.ClientSize.Width; // make room for the display object selectedRow.Height = display.Height; // tell it to display our row data display.displayRowData(selectedRow); // show the display display.Show(); } private void DGV_ColumnWidthChanged(object sender, DataGridViewColumnEventArgs e) { // enforce refresh on the display display.Refresh(); } 

以下是由显示对象中的按钮触发的测试操作:

 public void someAction(DataGridViewRow row) { Console.WriteLine(row.Index + " " + row.Cells[2].Value.ToString()); } 

当然你需要一个UserControl。 这是一个简单的,有两个标签,一个按钮和一个额外的标签关闭显示:

 public partial class UcRowDisplay : UserControl { public UcRowDisplay() { InitializeComponent(); } public delegate void someActionDelegate(DataGridViewRow row); public someActionDelegate button1Action { get; set; } DataGridViewRow myRow = null; public void displayRowData(DataGridViewRow row) { myRow = row; label1.Text = row.Cells[1].Value.ToString(); label2.Text = row.Cells[0].Value.ToString(); rowDisplayBtn1.Text = row.Cells[2].Value.ToString(); } private void rowDisplayBtn1_Click(object sender, EventArgs e) { button1Action(myRow); } private void label_X_Click(object sender, EventArgs e) { myRow.Selected = false; this.Hide(); } } 

它包含三个Labels和一个Button 在设计器中,它看起来像这样:

在这里输入图像说明

请注意,为了使我更容易,我已经修改了DGV

  • 没有RowHeader; 修改位置,如果你有一个。
  • 假定列标题具有与行相同的高度。
  • 所有(普通)行都具有相同的高度。
  • 将DGV设置为multiselect = false并且是只读的

更新

这里是一个滚动的简单例子:

 private void DGV_Scroll(object sender, ScrollEventArgs e) { DGV.PerformLayout(); var ccr = DGV.GetCellDisplayRectangle(0, selectedRow.Index, true); display.Top = ccr.Top + normalRowHeight; // ** display.Visible = (ccr.Top >= 0 && ccr.Height > 0); } 

这(**)假定所选行应保持可见。 SelectionChanged事件中应该会发生相同的计算! 水平滚动发生时应该怎么办?

请注意,在当前行之前添加或删除行时,需要进行类似的更新。 所以它应该被转移到你所谓的那些发生的功能上。