Jim McCurdy's Tech Blog

Insights into Software Development and Silverlight

The simplest way to detect DoubleClick in Silverlight

Here is a simple static class, MouseButtonHelper, that offers a single method, IsDoubleClick,  to determine if a standard MouseLeftButtonDown or MouseLeftButtonUp event is a double click.  In the past I have used timers, and Triggers and Behaviors to accomplish the same thing, but this approach is less code, less XAML, and uses a lot less resources.

Usage is as follows:

  • In XAML or in code behind, handle the standard MouseLeftButtonDown or MouseLeftButtonUp event for the object you wish to perform double click handling.
  • Implement the handler function for the above event as follows:
public void OnMouseButtonDown(object sender, MouseButtonEventArgs e)
{
	bool doubleClick = MouseButtonHelper.EventIsDoubleClick(sender, e);
	if (doubleClick)
		MessageBox.Show("Double click detected!", "Alert", MessageBoxButton.OK);
}

The code below has been tested and used with Silverlight 4.

using System;
using System.Windows;
using System.Windows.Input;

namespace ClassLibrary
{
	internal static class MouseButtonHelper
	{
		private const long k_DoubleClickSpeed = 500;
		private const double k_MaxMoveDistance = 10;

		private static long _LastClickTicks = 0;
		private static Point _LastPosition;
		private static WeakReference _LastSender;

		internal static bool IsDoubleClick(object sender, MouseButtonEventArgs e)
		{
			Point position = e.GetPosition(null);
			long clickTicks = DateTime.Now.Ticks;
			long elapsedTicks = clickTicks - _LastClickTicks;
			long elapsedTime = elapsedTicks / TimeSpan.TicksPerMillisecond;
			bool quickClick = (elapsedTime <= k_DoubleClickSpeed);
			bool senderMatch = (_LastSender != null && sender.Equals(_LastSender.Target));

			if (senderMatch && quickClick && position.Distance(_LastPosition) <= k_MaxMoveDistance)
			{
				// Double click!
				_LastClickTicks = 0;
				_LastSender = null;
				return true;
			}

			// Not a double click
			_LastClickTicks = clickTicks;
			_LastPosition = position;
			if (!quickClick)
				_LastSender = new WeakReference(sender);
			return false;
		}

		private static double Distance(this Point pointA, Point pointB)
		{
			double x = pointA.X - pointB.X;
			double y = pointA.Y - pointB.Y;
			return Math.Sqrt(x * x + y * y);
		}
	}
}

Comments (11) -

  • Hector

    8/5/2010 1:34:44 PM |

    Cool

    This really helpme a LOT ! !

  • Mosherot

    11/12/2010 6:15:07 AM |

    When I used custume usercontrols on a canvas and I wanted to doubleclick the object and the canvas separately - your code had problems - it detected both the usercontrol and the canvas. So i needed to change your code a little bit.
    Hopefully, this will serve someone else...Smile


    internal static class MouseButtonHelper
      {
        private const long k_DoubleClickSpeed = 500;
        private const double k_MaxMoveDistance = 10;

        private static long m_LastClickTicks = 0;
        private static Point m_LastPosition;
        private static object m_LastSender;
        
        internal static bool IsDoubleClick(object sender, MouseButtonEventArgs e)
        {
          bool senderMatch = sender.Equals(m_LastSender);
          long clickTicks = DateTime.Now.Ticks;
          Point position = e.GetPosition(null);
          long elapsedTicks = clickTicks - m_LastClickTicks;
          long elapsedTime = elapsedTicks / TimeSpan.TicksPerMillisecond;
          double distance = position.Distance(m_LastPosition);
          
          if (elapsedTime > k_DoubleClickSpeed){ // if overdue, no doubleclick
            m_LastClickTicks = clickTicks;
            m_LastPosition = position;
            m_LastSender = sender;
            return false;        
          }
          else if (senderMatch && elapsedTime <= k_DoubleClickSpeed && distance <= k_MaxMoveDistance)
          {
            // Double click!
            m_LastClickTicks = 0;
            m_LastSender = null;
            return true;
          }
              
          // Not a double click
          m_LastClickTicks = clickTicks;
          m_LastPosition = position;
          return false;
        }

        private static double Distance(this Point pointA, Point pointB)
        {
          double x = pointA.X - pointB.X;
          double y = pointA.Y - pointB.Y;
          return Math.Sqrt(x * x + y * y);
        }
      }

    Your code was VERY helpful and was really the best solution available. Thank you.

  • Alex

    1/5/2011 9:38:03 AM |

    You should use WeakReference to lastSender object in order to work correctly with GC

    • Jim McCurdy

      1/5/2011 11:25:16 AM |

      Good suggestion Alex.   I made the change to use a WeakReference, and also incorporated Mosherot's improvements.

      Thanks

  • Dave K

    10/27/2011 2:57:41 PM |

    This is a very nice solution indeed to the double click issue in Silverlight, thanks for sharing! BTW have you seen the following:

    msdn.microsoft.com/.../...clickcount(v=vs.96).aspx

    Looks like we'll be able to do things in a more standard way in SL5.

    Thanks again for the post, great solution.

    • jim mccurdy

      10/27/2011 3:31:01 PM |

      Yea, it will be a standard part of Silverlight 5.  In the mean time...

  • lambacini

    12/13/2011 8:04:49 AM |

    nice solution.really help me Smile
    Thanks.

  • André Nascentes

    1/6/2012 7:08:45 AM |

    Thanks a lot!

  • truyenle

    2/17/2012 5:49:37 PM |

    Cool! Simple and work like charm.

    Just a question, I'm using Accordion control as
    XAML
    ...
    xmlns:controls="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Layout.Toolkit"
    ...
    <controls:Accordion x:Name="Accordion" Margin="5" Grid.Row="0" Background="DarkGray" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
                                 ItemsSource="{Binding VideoStreams}">

    ...

    The result will be multi items will be added in Accordion, how to integrated your class so that the app detect double click on the child items not the Parent one (Accordion).

    many thanks for your share,.

  • Fiach

    3/2/2012 3:31:09 PM |

    Thank you so much! Smile

    Much better than the Silverlight toolkit!

  • downWithTheBass

    4/24/2012 2:43:08 PM |

    Perfect and simple! Thanks for this

Comments are closed