Skip to content →

Double Click behavior, mvvm compliant

Often when creating an application you will want a secondary mechanism for executing a command, the primary mechanism will often be a button click (e.g. Opening a record). In MVVM the backing ViewModel will expose an ICommand which is bound to the Button’s Command. This behavior executes the same command when a double click occurs.

Sample Application:

Install Microsoft Silverlight

How:

  • Register to the Mouse Up event on the AssociatedObject, we use the Mouse Up event so that we can attach the behavior to DataGrid / ListBox templates as the Mouse Down events are swallowed by these.
  • Create a dependancy property for the ICommand and the ClickInterval (this will commonly be hard coded by exists for demonstration purposes)
  • Set up a DispatcherTimer with the desired interval, also attach the Tick event and stop the timer.
  • When Mouse Up occurs event occurs the first time we start the DispatcherTimer.
  • For a double click to occur the Mouse Up event must be raised while the timer is active, if it is then we execute the Command and stop the timer.

Code:

public class DoubleClickBehavior : Behavior<UIElement>
{
    private readonly DispatcherTimer _timer = new DispatcherTimer();

    protected override void OnAttached()
    {
        base.OnAttached();
        AssociatedObject.MouseLeftButtonUp += AssociatedObjectMouseLeftButtonUp;
        _timer.Tick += new EventHandler(_timerTick);
        _timer.Interval = TimeSpan.FromSeconds(ClickInterval);
    }

    protected override void OnDetaching()
    {
        base.OnDetaching();
        AssociatedObject.MouseLeftButtonUp -= AssociatedObjectMouseLeftButtonUp;
    }

    private void _timerTick(object sender, EventArgs e)
    {
        _timer.Stop();
    }

    private void AssociatedObjectMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
    {
        if (!_timer.IsEnabled)
        {
            // If the timer is not already running then start it.
            _timer.Start();
        }
        else
        {
            _timer.Stop();
            if(CommandToExecute != null)
            {
                // If the timer is active there has been a second event so execute the command.
                CommandToExecute.Execute(this);

            }
        }
    }

    public static readonly DependencyProperty IntervalProperty =
        DependencyProperty.Register("ClickInterval",
        typeof(double),
        typeof(DoubleClickBehavior),
        new PropertyMetadata(0.25,
            new PropertyChangedCallback(OnClickIntervalChanged)));

    private static void OnClickIntervalChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args)
    {
        var doubleClick = (DoubleClickBehavior)sender;
        doubleClick._timer.Interval = TimeSpan.FromSeconds(doubleClick.ClickInterval);
    }

    public double ClickInterval
    {
        get { return (double)GetValue(IntervalProperty); }
        set { SetValue(IntervalProperty, value); }
    }

    public static readonly DependencyProperty CommandProperty =
        DependencyProperty.Register("CommandToExecute",
        typeof(ICommand),
        typeof(DoubleClickBehavior),
        new PropertyMetadata(null));

    public ICommand CommandToExecute
    {
        get { return (ICommand)GetValue(CommandProperty); }
        set { SetValue(CommandProperty, value); }
    }
}

Update:

xaml

Xaml

Source

Download solution

public class DoubleClickBehavior : Behavior<UIElement>
{
private readonly DispatcherTimer _timer = new DispatcherTimer();protected override void OnAttached()
{
base.OnAttached();
AssociatedObject.MouseLeftButtonUp += AssociatedObjectMouseLeftButtonUp;
_timer.Tick += new EventHandler(_timerTick);
_timer.Interval = TimeSpan.FromSeconds(ClickInterval);
}protected override void OnDetaching()
{
base.OnDetaching();
AssociatedObject.MouseLeftButtonUp -= AssociatedObjectMouseLeftButtonUp;
}private void _timerTick(object sender, EventArgs e)
{
_timer.Stop();
}private void AssociatedObjectMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
if (!_timer.IsEnabled)
{
// If the timer is not already running then start it.
_timer.Start();
}
else
{
if(CommandToExecute != null)
{
// If the timer is active there has been a second event so execute the command.
CommandToExecute.Execute(this);
}
}
}public static readonly DependencyProperty IntervalProperty =
DependencyProperty.Register(“ClickInterval”,
typeof(double),
typeof(DoubleClickBehavior),
new PropertyMetadata(0.25,
new PropertyChangedCallback(OnClickIntervalChanged)));

private static void OnClickIntervalChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args)
{
var doubleClick = (DoubleClickBehavior)sender;
doubleClick._timer.Interval = TimeSpan.FromSeconds(doubleClick.ClickInterval);
}

public double ClickInterval
{
get { return (double)GetValue(IntervalProperty); }
set { SetValue(IntervalProperty, value); }
}

public static readonly DependencyProperty CommandProperty =
DependencyProperty.Register(“CommandToExecute”,
typeof(ICommand),
typeof(DoubleClickBehavior),
new PropertyMetadata(null));

public ICommand CommandToExecute
{
get { return (ICommand)GetValue(CommandProperty); }
set { SetValue(CommandProperty, value); }
}
}

Published in Development

3 Comments

  1. Roni Roni

    Good approach. but how if we want to add CommandParameter on it?

    Thanks

  2. Dharmen Dharmen

    Thanks a lot for having such a good help but i have one question how to use this class in xaml which will catch the double click event so can you provide the source code for this demo sample applicaiton so that we can know how you have use this.
    I would really appreciate if you could help me out with this.

  3. jc jc

    @Dharmen
    Hi Dharmen,

    Thanks for the comment. I have updated the post to contain a xaml sample and the solution I made. You will need to add a reference to Expression blends Interactivity dll to attach the behavior

    Cheers,
    J

Leave a Reply

Your email address will not be published. Required fields are marked *

*

This site uses Akismet to reduce spam. Learn how your comment data is processed.