Windows 窗体 DataGridView 中的手风琴 [英] Accordion in Windows Forms DataGridView

查看:26
本文介绍了Windows 窗体 DataGridView 中的手风琴的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I need to implement some kind of accordion effect in a Windows Form DataGridView. When the user selects a row, the row is expanded to display some more information and if possible some buttons or other controls. The problem is, I have absolutely no clue, how to do this. I tried to search the web, but I found nothing that can lead me in the right direction in creating this. I hope someone can tell me how to do this? (does not have to be a code sample)

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

I created the below mockup to display what I want to do.

我想过调整列高并覆盖 OnPaint 方法.我只需要在第一个版本中显示一些文本.如果这是可能的,那就太好了.我知道将来我需要放置一些按钮或其他控件来对所选项目执行各种操作.如果实现起来非常复杂,我现在将跳过该部分.我知道我可以使用文本工具提示和按钮列等.但就我而言,我需要将其作为手风琴来做.

I thought about adjusting the columns height and override the OnPaint method. I only need to display some text in the first version. If that is possible that would be great. I know that in the future I would need to place some buttons or other controls to do various things with the selected item. If that is very complicated to achieve, I will skip that part for now. I know I could use tooltips for text and have button columns etc. but in my case, I need to do it as an accordion.

最好的问候汉斯·米林……

Best regards Hans Milling…

推荐答案

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

This is not really hard to do. The best approach would be to create a dedicated UserControl and overlay it at the right spot.

要为它腾出空间,只需更改行的Height,跟踪该行,以便在丢失选择时将其还原.

To make room for it simply change the Row's Height, keeping track of the row, so you can revert it when it looses selection.

您还必须决定是否可以展开多于一行,以及用户应该执行哪些操作来展开和重置该行..

You will also have to decide if more than one row can be expanded and just what the user is supposed to do to expand and to reset the row..

UserControl 可以有一个函数 displayRowData(DataGridViewRow row),你可以调用它来显示你对它的 Labels 感兴趣的字段等等.

The UserControl could have a function displayRowData(DataGridViewRow row) which you could call to display the fields you are interested in in its Labels etc..

您还应该制定关于 Buttons 如何与 DataGridView 交互的计划..

You should also have a plan on how the Buttons shall interact with the DataGridView..

如果你只想一次展开一行,你可以先创建UC,让DGV成为它的Parent并隐藏它.稍后在用户交互时,例如单击行或某个单元格,您会将其移动到右行并显示它..

If you only want one Row to be expanded at a time, you can create the UC up front, make the DGV its Parent and hide it. Later upon the user interaction, like clicking at the row, or a certain cell you would move it to the right row and show it..

如果可以扩展多于一行,您将需要创建多个 UC 并在 List 中跟踪它们..

If more than one row can be expanded you will need to create several UCs and keep track of them in a List..

这是一个鼓励您的最小示例..:

Here is a minimal example to encourage you..:

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();
}

这里是一个由显示对象中的按钮触发的测试动作:

Here is a test action triggered by the button in the display object:

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

当然你需要一个用户控件.这是一个简单的,有两个标签,一个按钮和一个额外的标签来关闭显示:

And of course you need a UserControl. Here is a simple one, with two Labels, one Button and one extra Label to close the display:

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.在设计器中它看起来像这样:

It contains tthree Labels and a Button. In the Designer it looks like this:

请注意,为了让我更轻松一些,我将 DGV 修改为

Note that in order to make it a little easier on me I have modified the DGV to

  • 没有RowHeader;如果有,请修改位置.
  • 假设列标题与行具有相同的高度.
  • 所有(正常)行具有相同的高度.
  • 将 DGV 设置为 multiselect=false 和只读

更新

以下是滚动的快速示例:

Here is a quick example for scrolling:

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 事件中!发生水平滚动时应该发生什么由您决定.

This (**) assumes the that the selected row shall remain visible. The same calculation should happen in the SelectionChanged event! It is up to you to decide what should happen when horizontal scrolling occurs..

请注意,在当前行之前添加或删除行时,需要类似的更新.所以它应该移到你在这些事件上调用的函数中..

Note that similar updates are necessary when rows are added or removed before the current row. So it should be moved to a function you call on those occurrances..

这篇关于Windows 窗体 DataGridView 中的手风琴的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆