Cleanest single click + double click handling in Silverlight?
Asked Answered
B

6

6

I've been finding various methods of dealing with double click and then the authors slap on some if code for handling single clicks. Is there a standard now in Silverlight 3 that everyone is using to handle both a single and a double click on listboxes?

Brigidabrigit answered 13/8, 2009 at 20:27 Comment(2)
I am very annoyed by the fact that double click and right click needs to be a hack in Silverlight...Megaera
I agree. I can see where a right click is problematic, but I would have thought double click was an easy thing.Brigidabrigit
T
10

If you use the Reactive Extensions (Rx) library the code to support double click is much simpler:

Observable.FromEvent<MouseButtonEventArgs>(myControl, "MouseLeftButtonDown").TimeInterval().Subscribe(evt =>
        {
            if (evt.Interval.TotalMilliseconds <= 300)
            {
                // Do something on double click
            }
        });
Torch answered 21/1, 2010 at 3:9 Comment(2)
Actually, this is wrong, although very slightly. One should check for Interval.TotalMilliseconds, because if you check for just Interval.Milliseconds, a doubleclick would also be at 2 hours, 3 minutes and 500 ms.Accede
Good catch, I've ammended this.Torch
B
2

Write once use easily....

 import YourProject.Utils; //must for using extentions

 button1.AddDoubleClickHandler((s, e) =>
            {
                Debug.WriteLine("You can use this DoubleClick extention method
                           for any UIElement in SL !");
            });         

//Here is my util

namespace YourProject.Utils
{
public class DoubleClick
{

    public DoubleClick()
    {
        this._lastClick = DateTime.Now;
    }

    private  TimeSpan DoubleClickThreshold = TimeSpan.FromMilliseconds(450);
    private  DateTime _lastClick;

    public event MouseButtonEventHandler MouseDoubleClick;

    public void DoubleClicked(object sender, MouseButtonEventArgs e)
    {
        if (DateTime.Now - this._lastClick <= DoubleClickThreshold)
        {
            MouseDoubleClick(sender, e);
        }
        this._lastClick = DateTime.Now;
    }

    internal void AddHandler(UIElement ctl)
    {
        ctl.AddHandler(UIElement.MouseLeftButtonUpEvent, new MouseButtonEventHandler(this.DoubleClicked), true);
    }
}

public static class DoubleClickExtentions
{
    public static void AddDoubleClickHandler(this UIElement ctl, MouseButtonEventHandler MouseDoubleClick)
    {
        DoubleClick doubleClick = new DoubleClick();
        doubleClick.MouseDoubleClick += MouseDoubleClick;

        doubleClick.AddHandler(ctl);
    }
}
}
Bield answered 14/8, 2012 at 11:49 Comment(0)
Z
1

I like this approach: http://www.domagoj.pavlesic.com/DoubleClick-in-Silverlight

Pros: you have single click, double click and single click delayed events (so you can be sure, there will be no double click).

Zinnia answered 24/1, 2011 at 13:22 Comment(0)
E
0

I've implemented a clean way to register for DoubleClick events based on the approaches of the following articles:

http://yinyangme.com/blog/post/The-simplest-way-to-detect-DoubleClick-in-Silverlight.aspx http://www.domagoj.pavlesic.com/DoubleClick-in-Silverlight

To use it, you just need to register/unregister the handler through extension methods:

element.AddDoubleClickHandler(Element_DoubleClick);
element.RemoveDoubleClickHandler(Element_DoubleClick);

Here is the code:

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

namespace System.Windows
{
    public class DoubleClickHelper
    {
        private const long DoubleClickSpeed = 500;
        private const double 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 <= DoubleClickSpeed);
            bool senderMatch = (lastSender != null && sender.Equals(lastSender.Target));

            if (senderMatch && quickClick && DoubleClickHelper.Distance(position, lastPosition) <= 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(Point pointA, Point pointB)
        {
            double x = pointA.X - pointB.X;
            double y = pointA.Y - pointB.Y;
            return Math.Sqrt(x * x + y * y);
        }

        public bool HasHandlers { get { return this.MouseDoubleClick != null; } }

        private WeakReference target;

        public event MouseButtonEventHandler MouseDoubleClick;
        private void OnMouseDoubleClick(MouseButtonEventArgs args)
        {
            if (this.MouseDoubleClick != null && this.target.IsAlive)
                this.MouseDoubleClick(this.target.Target, args);
        }

        public DoubleClickHelper(FrameworkElement target)
        {
            this.target = new WeakReference(target);

            target.MouseLeftButtonDown += target_MouseLeftButtonDown;
        }

        void target_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            if (DoubleClickHelper.IsDoubleClick(sender, e))
                this.OnMouseDoubleClick(e);
        }
    }

    public static class DoubleClickExtension
    {
        public static DoubleClickHelper GetDoubleClickHelper(DependencyObject obj)
        {
            return (DoubleClickHelper)obj.GetValue(DoubleClickHelperProperty);
        }
        public static void SetDoubleClickHelper(DependencyObject obj, DoubleClickHelper value)
        {
            obj.SetValue(DoubleClickHelperProperty, value);
        }
        public static readonly DependencyProperty DoubleClickHelperProperty =
            DependencyProperty.RegisterAttached("DoubleClickHelper", typeof(DoubleClickHelper), typeof(DoubleClickExtension), new PropertyMetadata(null));

        public static void AddDoubleClickHandler(this FrameworkElement target, MouseButtonEventHandler handler)
        {
            DoubleClickHelper helper = target.GetValue(DoubleClickHelperProperty) as DoubleClickHelper;
            if (helper == null)
            {
                helper = new DoubleClickHelper(target);
                target.SetValue(DoubleClickHelperProperty, helper);
            }

            helper.MouseDoubleClick += handler;
        }

        public static void RemoveDoubleClickHandler(this FrameworkElement target, MouseButtonEventHandler handler)
        {
            DoubleClickHelper helper = target.GetValue(DoubleClickHelperProperty) as DoubleClickHelper;
            if (helper == null) return;

            helper.MouseDoubleClick -= handler;
            if(!helper.HasHandlers)
                target.SetValue(DoubleClickHelperProperty, null);           

        }
    }
 }
Erotica answered 4/5, 2012 at 17:29 Comment(0)
A
0

There is an easier way in Silverlight 5, which supports MouseButtonEventArgs.ClickCount. So, you can just attach a normal MouseLeftButtonDown handler, and check:

private void OnMouseLeftButtonDown(object sender, MouseButtonEventArgs args)
{
    if (args.ClickCount == 1)
        return;

    // handle double-click
}
Alburga answered 10/4, 2014 at 19:13 Comment(0)
S
-1

Here's a class I've implemented for controls and also a second derived class below for a treeview (Silverlight Toolkit). Just instantiate it with the control you want to check for double clicks and add a handler for the DoubleClicked event. It uses a timer to try to simulate a double-click event. You can change the delay if you think it will work better.

Public Class DoubleClickHelper
Public Event DoubleClicked(ByVal sender As FrameworkElement)
Private WithEvents UI As FrameworkElement

Sub New(ByRef UI As FrameworkElement)
    Me.UI = UI
    UI.AddHandler(UIElement.MouseLeftButtonDownEvent, New MouseButtonEventHandler(AddressOf UI_MouseLeftButtonDown), True)
    InitTimer()
End Sub

Public Delay As Single = 0.2
Private _dblclick As Boolean = False
Private _timer As New System.Windows.Threading.DispatcherTimer()
Protected Property DoubleClick() As Boolean
    Get
        Return _dblclick
    End Get
    Set(ByVal value As Boolean)
        _dblclick = value
        InitTimer()
    End Set
End Property

Private Sub InitTimer()
    RemoveHandler _timer.Tick, AddressOf timer_Tick
    _timer.Stop()
    _timer = New System.Windows.Threading.DispatcherTimer()
    _timer.Interval = TimeSpan.FromSeconds(Delay)
    AddHandler _timer.Tick, AddressOf timer_Tick
    _timer.Start()
End Sub
Protected Overridable Sub timer_Tick(ByVal sender As Object, ByVal e As EventArgs)
    DoubleClick = False
End Sub

Protected Overridable Sub UI_MouseLeftButtonDown(ByVal sender As Object, ByVal e As System.Windows.Input.MouseButtonEventArgs) Handles UI.MouseLeftButtonDown
    If DoubleClick Then
        HandleDoubleClick(sender)
    Else
        HandleFirstClick(sender)
    End If
End Sub

Protected Overridable Sub HandleDoubleClick(ByVal sender As FrameworkElement)
    RaiseEvent DoubleClicked(sender)
End Sub

Protected Overridable Sub HandleFirstClick(ByVal sender As FrameworkElement)
    DoubleClick = True
End Sub

End Class

Public Class TreeViewItemDoubleClickHelper
Inherits DoubleClickHelper

Private SameSelection As Boolean = False
Private WithEvents TreeView As TreeView = Nothing

Public Sub New(ByVal TreeView As TreeView)
    MyBase.New(TreeView)
    Me.TreeView = TreeView
End Sub

'This event happens after MouseLeftButtonDown
Private Sub TreeView_SelectedItemChanged(ByVal sender As Object, ByVal e As System.Windows.RoutedPropertyChangedEventArgs(Of Object)) Handles TreeView.SelectedItemChanged
    SameSelection = e.OldValue Is e.NewValue
End Sub

Protected Overrides Sub UI_MouseLeftButtonDown(ByVal sender As Object, ByVal e As System.Windows.Input.MouseButtonEventArgs)
    'MyBase.UI_MouseLeftButtonDown(sender, e)
    If DoubleClick Or SameSelection Then
        HandleDoubleClick(sender)
        SameSelection = False
        DoubleClick = False
    Else
        HandleFirstClick(sender)
    End If
End Sub

End Class

Stutman answered 20/8, 2009 at 6:51 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.