1

I'm creating an application in C# using WinForms.

What I want:
I want a button with an arrow on the side. When the part of the button with the arrow is pressed it will display a drop down but if any other part of the button is pressed then it should trigger a mouse click event.

What I need help with:
I'm confident I can do the mouse positional check by using the mouse position, but how can I make sure the event handler for instances of the button only have a 'mouse button down' event when it was the main part of the button that was clicked? I.e. how do I eat the event in the base handler so it never reaches derived one?

What I have:
My code structure (simplified) is as follows (taken from Windows.Forms button with drop-down menu):

// Button class:
public class ButtonWithDropDown : Button
{
    protected override void OnClick(EventArgs e)
    {
        // Check for when the mouse is on the button and dispose of the
        // event if it's over the 'arrow' part of the button.
    }
}

// Event handler:
private void btnClickMe_Click(object sender, EventArgs e)
{
    MouseEventArgs mevent = (MouseEventArgs)e;
    if (mevent.Button == System.Windows.Forms.MouseButtons.Left)
        MessageBox.Show("Only shown when clicking the main part of the button");
}

Thanks.

Community
  • 1
  • 1
Edward
  • 235
  • 4
  • 18
  • Have an empty `override` in which you do not call the `base`. – David Pine Mar 18 '16 at 21:27
  • @David Pine Like in the example code? (My actual code does call `base.OnClick(e)`) Unfortunately I've tried removing it and it still passes the event through. – Edward Mar 18 '16 at 21:31
  • Are you trying to avoid the `.Click` event from having any listeners or are you trying to prevent the `override void OnClick` from being invoked altogether? – David Pine Mar 18 '16 at 21:35
  • Also, there are different events specific to the mouse... look at https://msdn.microsoft.com/en-us/library/system.windows.forms.control_events(v=vs.110).aspx – David Pine Mar 18 '16 at 21:37
  • I still want the 'Click()' event to fire but for the button to be consumed. For example if I could do `if (CursorNotInRightPlace()) mevent.Button = false;` that'd be great. But as far as I'm aware I can't do that. – Edward Mar 18 '16 at 21:45
  • You don't need to subscribe the event in your custom button class. There you should override `OnClick` and put the logic there. Also if you need any other event, you should create the event and raise it. – Reza Aghaei Mar 18 '16 at 21:48
  • It doesn't make sense that if you do not call `base.OnClick(e)` in your override of `OnClick`, the subscribing event handlers still get called. Are you genuinely sure you tested that properly? I suggest you make absolutely sure about that. – devuxer Mar 18 '16 at 22:18
  • @devuxer Using the code in my question and putting `ButtonWithDropDown btn = new ButtonWithDropDown(); btn.Location = new Point(100, 250); btn.MouseClick += btnClickMe_Click; this.Controls.Add(btn);` in `Form()` the message box is still displayed when the button's clicked (and it's the only message box in the entire solution). – Edward Mar 18 '16 at 22:27
  • 1
    `MouseClick` is a different event and if you don't like it to fire, you should override `OnMouseClick` and don't call `base.OnMouseClick(e)` – Reza Aghaei Mar 18 '16 at 22:38
  • Don't try to achieve this with one button, use two buttons and tug them together. – Martin Maat Mar 18 '16 at 22:40
  • I dont agree that *any* click event is the right one. In my splitbutton (== ButtonWithDropDown ??), in OnMouseDown I check which part of the button rect the mouse is over and act accordingly. If the menu should open, open it and/or raise any custom event effectively converting a click to a SplitClicked event. Not for nothing but there are 2-3 such beasts on CodeProject – Ňɏssa Pøngjǣrdenlarp Mar 18 '16 at 22:45
  • @RezaAghaei Thanks Reza, that worked. – Edward Mar 18 '16 at 22:58

1 Answers1

0

I think that the issue is that you were incorrectly wiring up Control.MouseClick instead of Control.Click. So, if you override the OnClick method, and hoping that it would prevent the OnMouseClick from being invoked you are mistaken.

There are lots of different events and each override maps to each event based on the naming convention of "On" plus the name of the event, for example:

┏━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ event name ┃ protected virtual method ┃
┣━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━━━┫
┃ Click      ┃ OnClick                  ┃
┃ MouseClick ┃ OnMouseClick             ┃
┃ ...        ┃ On...                    ┃
┗━━━━━━━━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━━━┛

The entire list exists here on MSDN. Additionally, you can view the source for the Control.cs here. You can easily see that all the events follow the same pattern, in that they are exposed for being overridden.

Ultimately you have complete control over your control by overriding the base behavior, assuming you handle the correct event.

David Pine
  • 23,787
  • 10
  • 79
  • 107