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 ...
随机推荐
- Java枚举类的serialVersionUID
起因 最近在公司里敲代码的时候偶然间发现以前留下的枚举类实现了Serializable接口,然后写了个serialVersionUID...我以前一直没在枚举类里使用过..觉得有点神奇....于是百度 ...
- 改bug的乐趣
一直以来,我都不喜欢改bug,不管是自己的,还是别人的.因为我不相信自己的代码会出现问题,一旦出现问题我就会觉得很难堪,因为我觉得我的代码没什么问题.然后我就不知道该怎么来解决这些问题. 最近这一两次 ...
- quartz简介
- textarea文本域的高度随内容的变化而变化
用css控制textarea文本域的高度随内容的变化而变化,不出现滚动条. CSS代码: 复制代码 代码如下: .t_area{ width:300px; overflow-y:visible } & ...
- linux安装mysql服务分两种安装方法:
linux安装mysql服务分两种安装方法: ①源码安装,优点是安装包比较小,只有十多M,缺点是安装依赖的库多,安装编译时间长,安装步骤复杂容易出错: ②使用官方编译好的二进制文件安装,优点是安装速度 ...
- 微信小程序相关一、模仿京东静态登录页面
一.培训的第一天,基本上没有什么最新的东西,但是看到老师的代码收获的确实是不少. 1.1.首页代码很简洁,将共有的样式都提取的很好. 1.2.其次是每一个小块写样式的时候用到了好多子代选择器和后代选择 ...
- Spark之 RDD转换成DataFrame的Scala实现
依赖 <dependency> <groupId>org.apache.spark</groupId> <artifactId>spark-sql_2. ...
- 344. Reverse String 最基础的反转字符串
[抄题]: [暴力解法]: 时间分析: 空间分析: [奇葩输出条件]: [奇葩corner case]: [思维问题]: 还停留在 i < len / 2的阶段,不行,应该是指针对撞问题了 [一 ...
- linux之shell编程初步
#################适用于CentOS6################## #!/bin/bash ########################################## ...
- [C++] Deep copy ,Shallow copy, copy constructor,"="
Deep copy ,Shallow copy, copy constructor,"=" Dog.h #pragma once class Dog { public: char ...