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 ...
随机推荐
- 【开发工具】Jenkins+Gitlab实现自动化部署
我在尝试在容器中安装Jenkins时,初衷是希望使用docker in docker 的模式来实现Jenkins slave容器按需创建.在实现的时候需要在Jenkins 中安装Kubernetes插 ...
- java 项目的jar 反编译后 压缩回去 命令
jar -cvfm0 123.jar META-INF\MANIFEST.MF(配置文件第一个位置) BOOT-INF org
- Linux实战教学笔记30:Nginx反向代理与负载均衡应用实践
1.1 集群简介 简单地说,集群就是指一组(若干个)相互独立的计算机,利用高速通信网络组成的一个较大的计算机服务系统,每个集群节点(即集群中的每台计算机)都是运行各自服务的独立服务器.这些服务器之间可 ...
- 【转】Pixel-Fillrate
[Pixel-Fillrate] “填充率“以每秒钟填充的像素点为单位,“三角形(多边形)生成速度“则表示每秒钟三角形(多边形)生成个数.现在的3D显卡的性能也主要看着两项指标,这两项指标的数值越大, ...
- 高性能Web服务器Nginx的配置与部署研究(9)核心模块之HTTP模块基本常用指令
一.HTTP模块的作用是什么? Nginx的HTTP模块用于控制Nginx的HTTP进程. 二.指令 1. alias 含义:指定location使用的路径,与root类似,但不改变文件的跟路径,仅适 ...
- 【原】Mac下统计任意文件夹中代码行数的工
[链接][原]Mac下统计任意文件夹中代码行数的工http://www.cnblogs.com/wengzilin/p/4580646.html
- c++ 享元模式(flyweight)
举个围棋的例子,围棋的棋盘共有361格,即可放361个棋子.现在要实现一个围棋程 序,该怎么办呢?首先要考虑的是棋子棋盘的实现,可以定义一个棋子的类,成员变量包括棋子的颜色.形状.位置等信息,另外再定 ...
- 16进制颜色转普通RGB
做开发的会遇到很多时候UI给到的是16进制的颜色 然而很多时候我们需要把它转换成适合我们方法的RGB参数 当然通过网页转换也可以达到目的 但是我现在选择写一个分类来解决 一劳永逸~ 1.首先说下 ...
- MySQL 时间函数加减计算
一.MySQL 获得当前日期时间 函数 1.1 获得当前日期 + 时间(date + time) 函数:now() mysql> select now();+———————+| now() |+ ...
- 关于防SQL注入敏感词过滤问题
关于对字符的过滤问题sql查询条件过滤掉单引号是否就安全了呢? 在文章最后一段管理员做了敏感字符的过滤,管理员过滤掉了空格,而攻击者通过 /**/ 来代替空格绕过了过滤字符.感觉很有成就感,呵呵呵呵. ...