WinForm中DataGridView的使用(四) - 区分单双击事件
虽然DataGridView单双击事件都有,但双击事件其实也会触发单击事件的处理,所以如果双击事件和单击事件的行为不同,或者双击时不想触发单击事件,或者单击事件会阻塞双击事件的处理时(比如单击后会有弹窗),就需要自行去实现了。
- 整体思路:
- 对于DataGridView当前页的每一行,维护一份点击信息,用于后续判断和处理。
- 两个线程或者说处理逻辑之间互相依赖。主线程的事件处理依赖timer线程去清理数据,比如在判断是否发生了双击时,其实隐含依赖于timer线程处理中未超时清理第一次点击标识;timer线程的处理逻辑依赖主线程的是否发生过一次点击和是否发生了双击的标识。
- 当点击某一行时(UI主线程)
- 如果是第一次点击,则标识这一行已经点击过一次了,并启动一个timer开始计时和处理(另一个线程)。
- 如果是第二次点击,则标识这一行发生了双击,这个标识用于timer中判断是否触发双击事件处理函数。
- timer的处理逻辑(timer线程)
- 这个timer运行到系统认为的双击间隔时间后(一定要跑到这个时间点,否则不知道是否会再有第二次点击)
- 如果没有再次发生第二次单击,则认为这一行是发生了双击事件,然后调用双击事件处理函数后,最后清理数据(以便下次判断单双击和计时)。
- 如果已经发生了第二次单击,则认为这一行是发生了单击事件,然后调用单击事件处理函数后,最后清理数据(以便下次判断单双击和计时)。
- 这个timer运行到系统认为的双击间隔时间后(一定要跑到这个时间点,否则不知道是否会再有第二次点击)
- 当点击某一行时(UI主线程)
- 缺点:即使只是单击,也要等到双击间隔接触才能确认不是单击,才能触发单击事件处理函数,感觉上有一点延迟,但这个逻辑貌似也是合理的。
- 即使发生连续点击多次的情况,也可以近似完美处理,因为主线程的事件处理肯定触发多次,第二次点击时已经设为了双击,timer事实上是只有达到双击间隔时才触发处理逻辑,并没有清理数据,所以大不了设置多次的双击标识。但timer的间隔可以考虑设置短一点,因为达到双击间隔后,最差情况下会经过一个间隔时间才会触发处理逻辑。
如果是自定义的一个DataGridView控件,需要定义一个单独的类,作为内部的列表或数组变量去储存DataGridView每一行对应的点击信息,用来区分单击还是双击。
/// <summary>
/// saved row click info to identify whether this mouse click is double click
/// </summary>
private RowClickInfo[] rowClickInfoOfCurrentPage;
详细类定义如下:
1 /// <summary>
2 /// click info for each data row to distinguish click and double click, and has a timer to execute single/double click action
3 /// </summary>
4 class RowClickInfo
5 {
6 public int CurRowIndex { get; set; }
7
8 /// <summary>
9 /// mark if the first click happened
10 /// </summary>
11 public bool HasFirstClickHappened { get; set; }
12
13 public bool IsDoubleClick { get; set; }
14
15 private int _milliseconds { get; set; }
16
17 /// <summary>
18 /// this timer is a must, or we don't know when to do single or double click action only using CellMouseDown event
19 /// </summary>
20 public System.Windows.Forms.Timer DoubleClickTimer { get; set; }
21
22 private const int _timerInterval = 100;
23
24 public RowClickInfo()
25 {
26 HasFirstClickHappened = false;
27 IsDoubleClick = false;
28 _milliseconds = 0;
29
30 DoubleClickTimer = new System.Windows.Forms.Timer();
31 DoubleClickTimer.Interval = _timerInterval;
32 DoubleClickTimer.Tick += new EventHandler(_doubleClickTimer_Tick);
33 }
34
35 private void _doubleClickTimer_Tick(object sender, EventArgs e)
36 {
37 _milliseconds += _timerInterval;
38
39 // if exceed double click time span, stop timer, do single/double click action and clear data
40 if (_milliseconds >= SystemInformation.DoubleClickTime)
41 {
42 DoubleClickTimer.Stop();
43
44 if (IsDoubleClick)
45 {
46 RowDoubleClick(CurRowIndex);
47 }
48 else
49 {
50 RowSingleClick(CurRowIndex);
51 }
52
53 // clear data
54 IsDoubleClick = false;
55 HasFirstClickHappened = false;
56 _milliseconds = 0;
57 }
58 }
59
60 public delegate void RowSingleClickHandler(int curRowIndex);
61 public event RowSingleClickHandler RowSingleClick;
62
63 public delegate void RowDoubleClickHandler(int curRowIndex);
64 public event RowDoubleClickHandler RowDoubleClick;
65 }
然后在绑定数据后要初始化当前页所有行的点击信息类:
// init row click info
rowClickInfoOfCurrentPage = new RowClickInfo[this.pageSize];
for (int i = ; i < this.pageSize; i++)
{
rowClickInfoOfCurrentPage[i] = new RowClickInfo();
rowClickInfoOfCurrentPage[i].CurRowIndex = i;
rowClickInfoOfCurrentPage[i].RowSingleClick += this.DataSourceRowClick;
rowClickInfoOfCurrentPage[i].RowDoubleClick += this.DataSourceRowDoubleClick;
}
接着在构造函数中绑定自定义的点击事件处理函数:
this.CellMouseDown += new DataGridViewCellMouseEventHandler(CellMouseDownHandler);
具体的点击事件处理函数如下:
/// <summary>
/// handle mouse down event of both single and double click event
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void CellMouseDownHandler(object sender, DataGridViewCellMouseEventArgs e)
{
int rowIndex = e.RowIndex;
if (rowIndex >= )
{
RowClickInfo curRowClickInfo = rowClickInfoOfCurrentPage[rowIndex];
if (!curRowClickInfo.HasFirstClickHappened)
{
// triggered the first time
curRowClickInfo.HasFirstClickHappened = true;
curRowClickInfo.DoubleClickTimer.Start();
}
else
{
// triggered the second time and it must be double click,
// because HasFirstClickHappened will change to false again if interval is too long
curRowClickInfo.IsDoubleClick = true;
}
}
}
WinForm中DataGridView的使用(四) - 区分单双击事件的更多相关文章
- WinForm中DataGridView的使用(三) - 各种事件
CellMouseDown/CellMouseUp 可获得行.列号 可用if (rowIndex >= 0 && e.Y > 4 && e.Y < ( ...
- WinForm中DataGridView复制选中单元格内容解决方案
WinForm中DataGridView鼠标选中单元格内容复制方案 1.CTR+C快捷键复制 前提:该控件ClipboardCopyMode属性设置值非Disable: 2.鼠标框选,自定义代码实现复 ...
- winform中dataGridView单元格根据值设置新值,彻底解决绑定后数据类型转换的困难
// winform中dataGridView单元格在数据绑定后,数据类型更改困难,只能迂回实现.有时候需要将数字变换为不同的文字描述,就会出现int32到string类型转换的异常,借助CellFo ...
- winform中dataGridView隔行显示不同的背景色,鼠标移动上显示不同颜色,离开后变回原色
winform中dataGridView隔行显示不同的背景色,鼠标移动上显示不同颜色,离开后变回原色 先设置奇数行颜色,这个有个自带的属性AlternatingRowsDefaultCellStyle ...
- 【接上一篇】winform中dataGridView高度和宽度自适应填充完数据的高度和宽度,即dataGridView根据数据自适应大小
上一篇:winform中dataGridView高度自适应填充完数据的高度 winform中dataGridView高度自适应填充完数据的高度,就是dataGridView自身不产生滚动条,自己的高度 ...
- winform中dataGridView高度自适应填充完数据的高度
// winform中dataGridView高度自适应填充完数据的高度,就是dataGridView自身不产生滚动条,自己的高度是根据数据的多少而变动. 在load的时候,数据绑定后,加上如下代码: ...
- C# Winform中DataGridView的DataGridViewCheckBoxColumn使用方法
下面介绍Winform中DataGridView的DataGridViewCheckBoxColumn使用方法: DataGridViewCheckBoxColumn CheckBox是否选中 在判断 ...
- js中字符串的replace方法区分单双引号
今天遇到一问题,js文件中调用字符串的replace方法,不起作用. 后来排查可能觉得replace("<option value='1'>admin</option&g ...
- winform中DataGridView实现分页功能
WinForm轻松实现自定义分页 (转载) WinForm轻松实现自定义分页 (转载) 转载至http://xuzhihong1987.blog.163.com/blog/static/26731 ...
随机推荐
- vector(实现存图)
#include<cstdio> #include<algorithm> #include<cstring> #include<iostream> #i ...
- UNITY 画布的粗浅理解
画布:当画布是screen-space overlay时,这个好理解,画布可以控制如分辨率,层次等.但当画布是 world-space时,这个严格来说就不算是一个画布了,屏幕空间或相机空间的画布是先绘 ...
- 如何将Excel日期快速转化为文本格式?
Excel表中日期格式其实是数值,有时候需要原样转成文本,有时候也要将文本转成日期. 我发现了一个方法,估计是最快的了.不需要用那一堆year() month()之类的函数. 快速将日期格式转化为文本 ...
- 架构之路:nginx与IIS服务器搭建集群实现负载均衡
http://blog.csdn.net/zhanghan18333611647/article/details/50811980
- Spring boot 开发组件
一.Jboot 描述:Jboot是一个基于jfinal 和 undertow开发的微服务框架.提供了AOP.RPC.分布式缓存.限流.降级.熔断.统一配置中心.swagger api自动生成.Open ...
- Python的内建比较函数cmp比较原理剖析-乾颐堂
cmp( x, y):比较2个对象,前者小于后者返回-1,相等则返回0,大于后者返回1. Python的cmp比较函数比较原理 Python的cmp函数可以比较同类型之间,或者不同数据类型之间.然后根 ...
- CentOS7.4配置SSH登录密码与密钥身份验证踩坑
简单记录,自用CentOS7.4虚拟机与ALiYunVPS,在配置ssh登录身份验证时碰到的问题. 阿里云VPS:因为在重置磁盘时选择了密钥对的身份验证方式,因此VPS中的CentOS7.4中的 /e ...
- mongodb 更新操作
db.aaaa.update({},{$push:{money:{$each:[8,9,10],$slice:-4}}}) db.aaaa.update({},{$addToSet:{money:{$ ...
- /var/run/yum.pid被锁定
当执行yum update时出现: /var/run/yum.pid已被锁定,PID为1610的另一个程序正在运行. 另外一个程序锁定了yum:等待它退出...... 解决办法 rm -f /var/ ...
- QT学习之窗口部件
对话框--QDialog 模态对话框与非模态对话框 模态对话框:就是相当于没关闭它之前,不能再和该应用程序的其他窗口进行交互(比如新建项目时弹出的对话框) 非模态对话框:可以与它交互,也可以与该程序中 ...