也许是因为Silverlight是跑在浏览器上的缘故,也许是Silverlight才刚刚起步,从设计之初到现在,它对鼠标事件的响应,仍然只有可怜的MouseLeftButtonDown、MouseLeftButtonUp、MouseEnter、MouseLeave和MouseMove五个事件而已。且不论它并没有对右键和滚轮(这个也许是为了跨平台,据说MacOS是没有滚轮的)的支持,就连双击这个简单的事件它也没有包装。因此,我自己写了一个Helper,实现了在Silverlight中的双击事件。
我仔细的研究了WinForm中的双击事件,我发现WinForm中的事件还真是多,和点击有关的事件,就有MouseClick、MouseDown、MouseUp、MouseDoubleClick、Click、DoubleClick等等。。。其实可以毫不客气的说,所有的事件都是对MouseDown和MouseUp的封装,但是这样的确可以让开发人员感到非常的方便。经过研究我发现,如果用户双击某一个控件,第一次点击会触发Click事件,第二次点击会触发DoubleClick而Click不会触发,同时这两次点击,都会触发MouseDown事件。
那么,我在Silverlight上的模拟,至少要达到这个要求。但是考虑到Silverlight上鼠标事件较少,又没有对右键的支持,因此我决定将情况分成两种,一种是双击的第一次会触发单击事件,另一种是双击后,两次点击都不会触发单击事件。我想,后一种也是有一定需求的,比如我做了一个MediaPlayer,我双击是为了全屏观看,单击是为了控制播放、暂停,这时如果双击的时候也触发了单击事件,那么全屏之后就暂停了,那多不爽啊。
其实通过监视MouseLeftButtonDown事件,可以很简单的模拟双击事件,只需要不停记录点击的时间,并且和上一次点击的时间比较,如果时间差小于某一个值,则触发双击事件,某则触发发单击事件。这样做,能够实现WinForm那种单双击的机制,但是无法实现我说的第二种机制,即双击的时候,单击永远不会触发。为了实现这个功能,我加入了一个Timer,当确定无法实现双击的时候,我会通过它来触发单击,这样做会造成单击事件触发有一定的延迟,但是这一点延迟也是微不足道的,毕竟双击的两次点击间隔也不是很长。该类的核心实现代码如下:
![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
Code
1
public class DoubleClickHelper
2![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
{
3![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
Constant#region Constant
4
private const long m_DoubleClickInterval = 2000000;
5
#endregion
6![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
7![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
Events#region Events
8
public event EventHandler<MouseButtonEventArgs> DoubleClick;
9
public event EventHandler<MouseButtonEventArgs> Click;
10
#endregion Events
11![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
12![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
Field#region Field
13
private DispatcherTimer m_Timer;
14
private bool m_IsSpecial;
15
private FrameworkElement m_Element;
16
private long m_DoubleClickTicks = 0;
17
private object Temp_Sender;
18
private MouseButtonEventArgs Temp_EventArgs;
19
#endregion
20![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
21![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
Property#region Property
22
private FrameworkElement Element
23![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
24![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
get
{ return m_Element; }
25
set
26![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
27
if (value != null && m_Element != value)
28![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
29
m_Element = value;
30
m_Element.MouseLeftButtonDown += new MouseButtonEventHandler(OnMouseLeftButtonDown);
31
}
32
}
33
}
34![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
35
public bool IsSpecial
36![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
37![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
get
{ return m_IsSpecial; }
38
set
39![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
40
m_IsSpecial = value;
41
if (IsSpecial)
42![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
43
this.m_Timer = new DispatcherTimer();
44
this.m_Timer.Interval = TimeSpan.FromTicks(m_DoubleClickInterval);
45
this.m_Timer.Tick += new EventHandler(m_Timer_Tick);
46
}
47
}
48
}
49
#endregion
50![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
51![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
Construstor#region Construstor
52
public DoubleClickHelper(FrameworkElement Element)
53![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
: this(Element, false)
{ }
54![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
55![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
56
public DoubleClickHelper(FrameworkElement Element, bool IsSpecial)
57![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
58
this.Element = Element;
59
this.IsSpecial = IsSpecial;
60
}
61
#endregion
62![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
63![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
Event Handlers#region Event Handlers
64
void m_Timer_Tick(object sender, EventArgs e)
65![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
66
RaiseSingleClick(Temp_Sender, Temp_EventArgs);
67
m_Timer.Stop();
68
}
69![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
70
void OnMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
71![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
72
if (IsSpecial)
73![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
74
Temp_Sender = sender;
75
Temp_EventArgs = e;
76
m_Timer.Start();
77
}
78![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
79
if (DateTime.Now.Ticks - m_DoubleClickTicks < m_DoubleClickInterval)
80![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
81
if (IsSpecial)
82
m_Timer.Stop();
83
RaiseDoubleClick(sender, e);
84
}
85
else
86![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
87
if (!IsSpecial)
88
RaiseSingleClick(sender, e);
89
}
90
m_DoubleClickTicks = DateTime.Now.Ticks;
91
}
92
#endregion
93![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
94![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
Raise Events#region Raise Events
95
void RaiseDoubleClick(object sender, MouseButtonEventArgs e)
96![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
97
if (DoubleClick != null)
98
DoubleClick(sender, e);
99
}
100![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
101
void RaiseSingleClick(object sender, MouseButtonEventArgs e)
102![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
103
if (Click != null)
104
Click(sender, e);
105
}
106
#endregion
107
}
对于这个类的用法,我认为很简单,只需要把你希望引发双击事件的UI元素(FrameworkElement)作为参数传递给这个类,并且为其规定双击是否在第一次点击触发单击即可(构造器已经重载,如果只传UI元素进去,那么默认与WinForm的机制是一样的)。但是值得一提的是,这个类是否能够使用,完全取决于它能否handle那个UI元素的MouseLeftButtonDown事件,由于一些特殊的原因,比如在某些类中,已经将MouseLeftButtonDown事件Handle过,并且将e.Handled设为true,那么我们将无法得知它何时触发MouseLeftButtonDown事件,还有如果事件路由被某些不可预测的原因阻击,那么我们也将无法得到MouseLeftButtonDown事件。因此,这个类也存在一定的局限性,不过还好,如果这个类不Work的话,那么你不用它而直接在代码里监视事件也不会Work,我做的也仅仅是对事件的进一步封装而已。
我做了一个测试,代码在这里:https://files.cnblogs.com/wodehuajianrui/DoubleClick.rar