首页 > 其他分享 >如何完美实现在DataGridView单元格中增加多个Button按钮?

如何完美实现在DataGridView单元格中增加多个Button按钮?

时间:2023-08-17 16:37:57浏览次数:44  
标签:ab Button 单元格 DataGridView AddButton dataGridView1 按钮

实现DataGridView多按钮操作列

在很多WinForm过程中,经常会遇到使用DataGridView进行编辑的场景,用户希望在最后放一个操作列,里面放置两个按钮,一个增加行的按钮,一个删除行的按钮;并且第一行只有增加行的按钮,没有删除行的按钮,大概的界面如下:

如何完美实现在DataGridView单元格中增加多个Button按钮?_Button

DataGridView本身提供了DataGridViewButtonColumn列类型,但问题是只会放置一个Button在单元格里,不能满足我们的需求;通过网络搜索,有很多实现方案,最终选用了通过动态生成按钮的方案,并根据所在单元格的显示范围动态设置大小和位置。

该方案在实现过程有一些细节需要注意,否则会影响用户的使用体验,先记录如下,希望为后面有需要的朋友提供一些帮助,需要的朋友可到文章末尾获取完整源码,直接复制到自己的项目可用。

一、监控DataGridView的RowsAdded、RowsRemoved事件进行按钮的动态生成和移除

首先是动态生成按钮的时机,一定要在DataGridView的RowsAdded和RowsRemoved事件中去做,否则就需要再所有用户增加行的代码处都增加动态生成按钮的代码,对于后期的代码维护很不友好;而放在RowsAdded事件和RowsRemoved事件中可以一劳永逸的解决这个问题,代码如下:

private void dataGridView1_RowsAdded(object sender, DataGridViewRowsAddedEventArgs e)
{
	Button btnAdd = new Button();
	btnAdd.Text = "+";
	btnAdd.Click += onAddButtonClick;
	dataGridView1.Controls.Add(btnAdd);

	Button btnRemove = new Button();
	btnRemove.Text = "-";
	btnRemove.Click += onRemoveButtonClick;
	dataGridView1.Controls.Add(btnRemove);

	...
}

private void dataGridView1_RowsRemoved(object sender, DataGridViewRowsRemovedEventArgs e)
{
    int rowIndex = e.RowIndex;
	if (rowIndex >= 0 && rowIndex < mButtons.Count)
	{
		ActionButtons ab = mButtons[rowIndex];
		ab.AddButton.Visible = false;
		ab.AddButton.Dispose();
		ab.RemoveButton.Visible = false;
		ab.RemoveButton.Dispose();

		...
	}
}
二、使用列表按行顺序保存动态生成的按钮,用以支持按钮移除和按钮位置跟新

由于用户对于DataGridView的行操作是不可以允许,可能删除任意一行,也可能在任意一行后面插入,所以我们需要记录每个按钮对应的行索引,以便于后期更新时使用;为了将增加、删除按钮方便的存储并和对应的行进行映射,我们定义了一个ActionButtons类,将每一行对应的按钮都记录在ActionButtons实例中,并按顺序存入List表中,ActionButtons实例在List列表中的的索引号即是对应的DataGridView行号,代码如下:

internal class ActionButtons
{
    public ActionButtons(Button addButton, Button removeButton)
    {
        AddButton = addButton;
        RemoveButton = removeButton;
    }

    public Button AddButton { get; set; }
    public Button RemoveButton { get; set; }
}

List<ActionButtons> mButtons = new List<ActionButtons>();

private void dataGridView1_RowsAdded(object sender, DataGridViewRowsAddedEventArgs e)
{
	Button btnAdd = new Button();
	btnAdd.Text = "+";
	btnAdd.Click += onAddButtonClick;
	dataGridView1.Controls.Add(btnAdd);

	Button btnRemove = new Button();
	btnRemove.Text = "-";
	btnRemove.Click += onRemoveButtonClick;
	dataGridView1.Controls.Add(btnRemove);

	mButtons.Add(new ActionButtons(btnAdd, btnRemove));
}

private void dataGridView1_RowsRemoved(object sender, DataGridViewRowsRemovedEventArgs e)
{
    int rowIndex = e.RowIndex;
	if (rowIndex >= 0 && rowIndex < mButtons.Count)
	{
		ActionButtons ab = mButtons[rowIndex];
		ab.AddButton.Visible = false;
		ab.AddButton.Dispose();
		ab.RemoveButton.Visible = false;
		ab.RemoveButton.Dispose();

		mButtons.RemoveAt(rowIndex);
	}
}
三、监控DataGridView的Scroll、SizeChanged事件进行按钮的位置更新和显隐控制
在用户操作的过程中,有几个场景会需要对按钮的位置进行设置:
  • 新增的时候对按钮位置进行初始化。
  • 垂直滚动条由无到有时,按钮的位置需要更新;反之亦然。
  • 滚动条发生滚动时,按钮的位置需要更新。
  • DataGridView列宽度发生改变时,按钮的位置需要更新。
  • DataGridView大小发生变化时,按钮的位置需要更新。
同样,有几个场景会需要对按钮进行显隐状态的控制:
  • 当按钮所在行不在DataGridView显示范围内时要对按钮进行隐藏。
  • 当按钮所在行被删除时要对按钮进行隐藏。
  • DataGridView列宽度发生改变时,按钮的位置需要更新。

每次对位置和显隐的更新都需要遍历所有按钮,并且将更新代码放到线程中执行,以避免行增加、删除的同步操作对判断产生影响,具体代码如下:

private void HideAllActionButtons(ActionButtons ab)
{
    dataGridView1.BeginInvoke(() =>
    {
    	ab.AddButton.Visible = ab.RemoveButton.Visible = false;
    });
}

private void UpdateActionButtonsPosition(ActionButtons ab, Rectangle rect, int rowIndex)
{
    dataGridView1.BeginInvoke(() =>
    {
    	ab.AddButton.Location = new Point(rect.Left + 5, rect.Top + 5);
    	ab.AddButton.Size = new Size(rect.Width / 2 - 10, rect.Height - 10);
    	ab.AddButton.Visible = true;

    	ab.RemoveButton.Location = new Point(ab.AddButton.Left + ab.AddButton.Width + 5, rect.Top + 5);
    	ab.RemoveButton.Size = ab.AddButton.Size;
    	ab.RemoveButton.Visible = rowIndex > 0;
    });
}

private void RepositionActionButtons()
{
    Task.Run(() =>
    {
         Thread.Sleep(100);

         int firstRow = dataGridView1.FirstDisplayedScrollingRowIndex;
         int lastRow = firstRow + dataGridView1.DisplayedRowCount(false);

         for (int i = 0; i < mButtons.Count; i++)
         {
             ActionButtons ab = mButtons[i];
             ab.AddButton.Tag = i;
             ab.RemoveButton.Tag = i;

             if (i >= firstRow && i <= lastRow)
             {
                 Rectangle rect = dataGridView1.GetCellDisplayRectangle(btnColIndex, i, false);
                 UpdateActionButtonsPosition(ab, rect, i);
             }
             else
             {
                 HideAllActionButtons(ab);
             }
         }
     });
}

private void dataGridView1_Scroll(object sender, ScrollEventArgs e)
{
    RepositionActionButtons();
}

private void dataGridView1_SizeChanged(object sender, EventArgs e)
{
    RepositionActionButtons();
}

private void dataGridView1_ColumnWidthChanged(object sender, DataGridViewColumnEventArgs e)
{
    RepositionActionButtons();
    this.Refresh();
}
注:在列宽度发生改变时,多调用了一个Refresh方法,用于刷新界面;是因为在拖动列改变宽度时有可能会再按钮表面留下拖动的痕迹,通过刷新可以恢复按钮的样式。

最终的效果如下图:

如何完美实现在DataGridView单元格中增加多个Button按钮?_Button_02

以上功能以在实际项目中使用,效果完美,有需要的朋友可通过下方链接获取完整代码,将其中的内容复制到自己的项目中即可。

下载源码

标签:ab,Button,单元格,DataGridView,AddButton,dataGridView1,按钮
From: https://blog.51cto.com/u_16229237/7123655

相关文章

  • 使用hutool给excel单元格标黄和添加批注
    packagecom.yc.cloud.excel.util;importcn.hutool.poi.excel.ExcelWriter;importlombok.extern.slf4j.Slf4j;importorg.apache.poi.hssf.usermodel.HSSFClientAnchor;importorg.apache.poi.hssf.usermodel.HSSFRichTextString;importorg.apache.poi.ss.usermodel.......
  • CF1858A Buttons题解
    思路我们可以让两人先拿\(c\)里面的,因为\(a\)和\(b\)肯定是自己的,那么公共的“我”也要抢的越多越好,所以我们都要先拿\(c\)里面的。如果\(c\)是奇数,那么先手一定多拿\(1\)个\(c\)里面的,相当于先手可以拿\(a+1\)个,后手可以拿\(b\)个;如果\(c\)是偶数,那么两......
  • vue2使用table进行单元格合并,后面列合并需根据前某列条件合并
    示例:<tableclass="table_style"><thead><tr><td>姓名</td><td>年龄</td><td>车辆</td>&......
  • 【Excel第二讲】单元格格式设置
     数字格式学习表汇总 ......
  • Wordpress:如何使用Elementor给页面Button做跳转页面锚点定位?
    网站页面有的关键部分不一定在页面首屏,但是如果其它页面有时候需要做跳转,比如联系框,需要直接跳转到联系框的实际位置,在使用Elementor插件的情况下,如何实现呢?前端技术告诉我们,要实现点击a标签或者按钮跳转到指定位置,可以使用id定位,并在跳转链接后加入#符号附带该ID即可如: ......
  • excel wps宏编辑器,用JavaScript自定义函数设置单元格符合条件后,那一行都变色
        functionjudge(){varapp=Application;//WPS表格的应用程序对象varwb=app.ActiveWorkbook;//当前工作簿varsheet=wb.ActiveSheet;//当前工作表vardataRange=sheet.UsedRange;//使用的数据范围varnumRows=dataRange.Rows......
  • Java读取Excel中的合并单元格
    1、 Maven仓库下载导入在pom.xml中配置maven路径,指定依赖,如下:<dependency><groupId>org.apache.poi</groupId><artifactId>poi</artifactId><version>4.1.1</version></dependency><dependency><groupId>......
  • 从 Word 复制表格到 Excel 如何保留多行单元格
    思路是在Word中将换行符替换为一串自定义的文本,然后将其粘贴到Excel中,再在Excel中将特殊文本替换回换行。具体可参考下面的链接。Retainmulti-linecellswhenpastingWordtableintoExcel-MicrosoftCommunityHowdoIcopyWordtablesintoExcelwithoutsplitt......
  • python获取Excel文件中单元格公式的计算结果
    importopenpyxl#打开Excel文件wb=openpyxl.loadworkbook('data.xlsx',data_only=True)#获取WorkSheetws=wb.worksheets[0]forrowinws.rows:print(row[0].value)注意:使用openpyxl读取公式计算结果时,如果无法得到正确结果时会读出None,此时需要打开对应的excel......
  • 【MFC】CListCtrl 如何设置单元格颜色?
    CListCtrl默认可设置的内容很少,如单元格颜色默认无法设置。若想设置单元格颜色,需要对CListCtrl进行拓展,已有老外为我们写好demo,这里对其中原理、设置方法进行一个解析。其原理是:设置CListCtrl控件的OwerDraw属性为true,然后使用GDI画图函数进行各种自定义绘制。拓展的类为CColor......