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); }
}
}