How do I get a DoubleClick event in a .NET radio button?
Asked Answered
B

5

10

I'd like to be able to catch the DoubleClick or MouseDoubleClick events from a standard winforms radio button, but they seem to be hidden and not working. At the moment I have code like this:

public class RadioButtonWithDoubleClick : RadioButton
{
    public RadioButtonWithDoubleClick()
        : base()
    {
        this.SetStyle( ControlStyles.StandardClick | ControlStyles.StandardDoubleClick, true );
    }

    [EditorBrowsable( EditorBrowsableState.Always ), Browsable( true )]
    public new event MouseEventHandler MouseDoubleClick;
    protected override void OnMouseDoubleClick( MouseEventArgs e )
    {
        MouseEventHandler temp = MouseDoubleClick;
        if( temp != null ) {
            temp( this, e );
        }
    }
}

Is there a simpler and cleaner way to do it?

Edit: For background, I agree with Raymond Chen's post here that the ability to double click on a radio button (if those are the only controls on the dialog) makes the dialog just a tiny bit easier to use for people who know about it.

In Vista using Task Dialogs (see this Microsoft guideline page or this MSDN page specifically about the Task Dialog API) would be the obvious solution, but we don't have the luxury of that.

Briquet answered 30/6, 2009 at 14:51 Comment(0)
P
11

Based on your original suggestion I made a solution without the need to subclass the radiobuton using reflection:

MethodInfo m = typeof(RadioButton).GetMethod("SetStyle", BindingFlags.Instance | BindingFlags.NonPublic);
if (m != null)
{
    m.Invoke(radioButton1, new object[] { ControlStyles.StandardClick | ControlStyles.StandardDoubleClick, true });
}
radioButton1.MouseDoubleClick += radioButton1_MouseDoubleClick;

Now the double click event for the radiobutton is fired. BTW: The suggestion of Nate using e.Clicks doesn't work. In my tests e.Clicks was always 1 no matter how fast or often I clicked the radiobutton.

Pleasant answered 3/9, 2010 at 13:55 Comment(0)
G
3

You could do something like this:

myRadioButton.MouseClick += new MouseEventHandler(myRadioButton_MouseClick);

void myRadioButton_MouseClick(object sender, MouseEventArgs e)
{
    if (e.Clicks == 2)
    {
         // Do something
    }
}

You may or may not also want to check that e.Button == MouseButtons.Left

Geotropism answered 30/6, 2009 at 17:34 Comment(3)
I'm accepting this one, because although I think my own solution is simpler for my case, where I'm going to be using the same control many times, if someone just wanted one or two then yours is much simpler.Briquet
This does not seem to be working on .NET 3.5 as the Clicks == 2 never happens.Faxan
This doesn't happen in .NET 4.0 either, so I'm switching the accepted answer to the reflection-based one by MSW.Briquet
B
1

Based on @MSW answer, I made this extension class:

static class RadioButtonEx
{
    public static void AllowDoubleClick(this RadioButton rb, MouseEventHandler MouseDoubleClick)
    {
        //
        // Allow double clicking of radios
        System.Reflection.MethodInfo m = typeof(RadioButton).GetMethod("SetStyle", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic);
        if (m != null)
            m.Invoke(rb, new object[] { ControlStyles.StandardClick | ControlStyles.StandardDoubleClick, true });

        rb.MouseDoubleClick += MouseDoubleClick;
    }
}

Which is then super easy to set up and re-use:

radioButton.AllowDoubleClick((a, b) => myDoubleClickAction());
Bidden answered 28/1, 2016 at 9:33 Comment(0)
B
0

Sorry, don't have the reputation to comment on this. What action are you trying to have the double-click perform for the user? I think using a double-click may be confusing because it is different from the general mental model that a user has of a radio-button (IE single click, select one option from a set)

Baneful answered 1/7, 2009 at 3:9 Comment(2)
Ah, I see. You are using the double-click as a shortcut for select+next. That makes sense. I think the code you presented is the cleanest way to go about this. Looks like this is functionality that MS tried to intentionally bury for the radiobutton.Baneful
That's what I figured :( Thanks for the feedback.Briquet
D
0

This is probably not as relevant as it was at the time of release, but there is still such an option.

public partial class DoubleClickDetector : Component
{
    #region Public Fields

    public const int UnknownId = int.MinValue;

    #endregion Public Fields

    #region Private Fields

    private readonly Stopwatch stopwatch = Stopwatch.StartNew();

    private int lastId = UnknownId;

    private long lastMS;

    private int lastX;

    private int lastY;

    #endregion Private Fields

    #region Public Constructors

    public DoubleClickDetector() => InitializeComponent();

    public DoubleClickDetector(IContainer container)
    {
        container.Add(this);
        InitializeComponent();
    }

    #endregion Public Constructors

    #region Public Methods

    public bool Detect(int id, int x, int y)
    {
        long elapsedMS = stopwatch.ElapsedMilliseconds;
        bool isDouble = id != UnknownId && lastId == id && elapsedMS - lastMS <= SystemInformation.DoubleClickTime &&
            Math.Abs(lastX - x) <= SystemInformation.DoubleClickSize.Width &&
            Math.Abs(lastY - y) <= SystemInformation.DoubleClickSize.Height;
        lastId = isDouble ? UnknownId : id;
        lastMS = elapsedMS;
        lastX = x;
        lastY = y;
        return isDouble;
    }

    #endregion Public Methods
}

It looks a bit bulky, but it allows to detect double clicks without using reflection, so it is actually a lightweight object. Also, it can be rewritten as a non-component class for further optimization.

It can be used in a simple way with some constants to specify controls.

private void radioButtonYes_MouseUp(object sender, MouseEventArgs e)
{
    if (e.Button == MouseButtons.Left && doubleClickDetectorMain.Detect(0, e.X, e.Y)) buttonOk.PerformClick();
}
Doucette answered 21/3 at 23:51 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.