Windows窗体DataGridView中的Accordion

niv*_*978 2 c# forms windows datagridview accordion

我需要在Windows窗体DataGridView中实现某种手风琴效果.当用户选择一行时,该行将展开以显示更多信息,如果可能,还会显示一些按钮或其他控件.问题是,我完全不知道如何做到这一点.我试图搜索网络,但我发现没有任何东西可以引导我在正确的方向上创建它.我希望有人能告诉我怎么做?(不一定是代码示例)

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

我考虑过调整列高度并覆盖OnPaint方法.我只需要在第一个版本中显示一些文本.如果那可能会很棒.我知道将来我需要放置一些按钮或其他控件来对所选项目进行各种操作.如果实现起来非常复杂,我现在将跳过这一部分.我知道我可以使用工具提示文本和按钮列等.但在我的情况下,我需要做手风琴.

带手风琴样机的DataGridView

最好的问候Hans Milling ......

TaW*_*TaW 7

这真的不难做到.最好的方法是创建一个专用的UserControl并在正确的位置叠加它.

要为它腾出空间,只需更改Row Height,跟踪行,这样您就可以在选择失败时还原它.

您还必须决定是否可以扩展多行,以及用户应该做什么来扩展和重置行.

UserControl可以有一个功能displayRowData(DataGridViewRow row),你可以调用显示你有兴趣在其领域Labels等.

你还应该有一个如何ButtonsDataGridView... 互动的计划.

如果您只希望一次扩展一行,则可以创建UC前面的,创建DGVParent并隐藏它.稍后在用户交互时,例如点击该行或某个单元格,您可以将其移动到右侧并显示它.

如果可以扩展多行,则需要创建多个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;
}
Run Code Online (Sandbox Code Playgroud)

填完DGV之后

    // store the normal row height
    normalRowHeight = DGV.Rows[0].Height;
Run Code Online (Sandbox Code Playgroud)

你至少需要这些事件:

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();
}
Run Code Online (Sandbox Code Playgroud)

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

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

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

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();
    } 
}
Run Code Online (Sandbox Code Playgroud)

它包含tthree Labels和a Button.在Designer中它看起来像这样:

在此输入图像描述

请注意,为了使我更容易,我已将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);
}
Run Code Online (Sandbox Code Playgroud)

这(**)假定所选行保持可见.SelectionChanged事件中应该进行相同的计算!您可以决定在水平滚动发生时应该发生什么.

请注意,在当前行之前添加或删除行时,必须进行类似的更新.所以它应该被移动到你调用那些出现的函数上.