Monday, August 24, 2009

Mouse DoubleClick in Silverlight

We are implementing a mouse-doubleclick event in the TimeLine Visualizer control, but that is not native to Silverlight. There are a number of code snippets on the web about how to do this, but I think the implementation of the event is nice enough to share here.

The event fires when the mouse is clicked twice within a certain time, and within a certain distance. I think the spatial/temporal tolerances make for a smooth user experience. The code consists of static variables to store the position and time of last mouse-click, and extension methods to compare the current values to the stored values. The code should be self-explanatory (While we are one the subject, can anybody point me to a good online code formatter for blogger? Live Writer refuses to install on my machine which has Windows 7 Ultimate, 32-bit):

1:      #region Mouse Double Click  
2: //initialize to 2 secs back, so event doesnt fire very first time user clicks on control
3: static DateTime _lastClicked = DateTime.Now.AddSeconds(-2);
4: static Point _lastMousePosition = new Point(1, 1);
5: private const double MousePositionTolerance = 20;
6: public static bool IsDoubleClick(this MouseButtonEventArgs e)
7: {
8: bool ret = false;
9: if ((DateTime.Now.Subtract(_lastClicked) < TimeSpan.FromMilliseconds(500))
10: && (e.GetPosition(null).GetDistance(_lastMousePosition) < MousePositionTolerance))
11: {
12: ret = true;
13: }
14: _lastClicked = DateTime.Now;
15: _lastMousePosition = e.GetPosition(null);
16: return ret;
17: }
18: #endregion
19: public static double GetDistance(this Point current, Point other)
20: {
21: double x = current.X - other.X;
22: double y = current.Y - other.Y;
23: return Math.Sqrt(x * x + y * y);
24: }


The consumer code will handle the MouseLeftButtonDown event and examine it to see if it is a double-click, like this:

private void HandleMouseLeftButtonDown(object sender, MouseButtonEventArgs e)

{

if (e.IsDoubleClick())

{
....

Caveat Emptor:
The calling method should make sure that all code paths execute e.DoubleClick().

Take, for instance, a calling method like this:

if (condition1 == true)
{
condition1 = false;
do something;
}
else if (e.IsDoubleClick())
{
Do what you do on doubleclick;
}

Here IsDoubleClick is not called the first time the Mousedown event happens, so the static variables _lastPosition and _lastClicked are not set. Hence, IsDoubleClick will not return true when a true double-click happens.

Hope this helps.

2 comments:

  1. Pretty elegant in that it takes advantage of the single threaded nature of silverlight. Thanks for posting the is.

    ReplyDelete
  2. hey its really nice............and working fine too............
    VB.net code for same is as.................
    #Region "Mouse Double Click"
    'initialize to 2 secs back, so event doesnt fire very first time user clicks on control
    Dim _lastClicked As DateTime = DateTime.Now.AddSeconds(-2)
    Dim _lastMousePosition As New Point(1, 1)
    Private Const MousePositionTolerance As Double = 20
    _
    Public Function IsDoubleClick(e As MouseButtonEventArgs) As Boolean
    Dim ret As Boolean = False
    If (DateTime.Now.Subtract(_lastClicked) < TimeSpan.FromMilliseconds(500)) AndAlso (e.GetPosition(Nothing).GetDistance(_lastMousePosition) < MousePositionTolerance) Then
    ret = True
    End If
    _lastClicked = DateTime.Now
    _lastMousePosition = e.GetPosition(Nothing)
    Return ret
    End Function
    #End Region
    _
    Public Shared Function GetDistance(current As Point, other As Point) As Double
    Dim x As Double = current.X - other.X
    Dim y As Double = current.Y - other.Y
    Return Math.Sqrt(x * x + y * y)
    End Function

    ReplyDelete