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 ...
随机推荐
- **利用列表和super实现有序字典
class MyDict(dict): def __init__(self): self.temp_list = [] super(MyDict,self).__init__() def __seti ...
- Windows Server 2003 简体中文企业版
Windows Server 2003 简体中文企业版,真正免激活. CD-KEY:JB88F-WT2Q3-DPXTT-Y8GHG-7YYQY 安装序列号:JCGMJ-TC669-KCBG7-HB8X ...
- U3D中的又一个坑
using System.Collections; using System.Collections.Generic; using UnityEditor; using UnityEngine; pu ...
- java多线程-慎重使用volatile关键字
Java语言包含两种内在的同步机制:同步块(或方法)和 volatile 变量.这两种机制的提出都是为了实现代码线程的安全性.其中 Volatile 变量的同步性较差(但有时它更简单并且开销更低),而 ...
- 在SharePoint解决方案中使用JavaScript (1) – 引用.js文件
本文是系列文章的第一篇. 在SharePoint解决方案中使用JavaScript (0) 作为在SharePoint应用程序中使用JavaScript的第一步,就是要知道如何将一个写好的.js文件, ...
- 最长的相同节点值路径 · Longest Univalue Path
[抄题]: Given a binary tree, find the length of the longest path where each node in the path has the s ...
- 单例模式的N种写法
单例模式算是设计模式中最容易理解,也是最容易手写代码的模式了吧.但是其中的坑却不少,所以也常作为面试题来考.本文主要对几种单例写法的整理,并分析其优缺点.很多都是一些老生常谈的问题,但如果你不知道如何 ...
- xargs在linux中的使用详解-乾颐堂
xargs在linux中是个很有用的命令,它经常和其他命令组合起来使用,非常的灵活. xargs是给命令传递参数的一个过滤器,也是组合多个命令的一个工具.它把一个数据流分割为一些足够小的块,以方便过滤 ...
- C#变量初始化
在C#中声明变量使用下述语法: datatype identifier;, 例如: int i; 该语句声明int变量i.编译器不允许在表达式中使用这个变量,除非用一个值初始化了改变量.如果你不需要使 ...
- logback与log4j比较
摘自:https://www.cnblogs.com/smile361/p/7592684.html logback与log4j比较 更快的执行速度: 基于我们先前在log4j上的工作,logback ...