3

I have a custom control (custom ComboBox). It`s work well, when I press "arrow button" it deployed, if I press it again it deployed too, but if it are deployed and I press anywhere in my form - it close but then, when I'm trying to open it - I must press "arrow button" two times. So I need to detect this moment, when I click outside of my combobox.

Code to open ComboBox(call in ButtonClick)

private void OpenComboBox()       
{
    if (drop_flag)
    {
        ...

        popup.Show(this);
    }
    else
    {
        drop_flag = true;
    }
}

And Close event

private void popup_Closed(object sender, ToolStripDropDownClosedEventArgs e)
{
    drop_flag = false;
}

So, I want something like this

private ClickedOutsideControl()
{
    dropflag = true;
}
Cœur
  • 37,241
  • 25
  • 195
  • 267
Udjen
  • 91
  • 1
  • 9
  • This makes no sense. The only logical usage of *drop_flag* is `if (!drop_flag) { /* show dropdown */ }`. – Hans Passant Dec 30 '13 at 13:56
  • You offer will always show dropdown, and never close it by clicking on the button – Udjen Dec 30 '13 at 13:59
  • The behavior I observe is slightly different than what you describe. When a ComboBox drop-down-list is opened and you click on another control, this other control is not activated. Instead the drop-down closes and you must click on the other control again to activate it. If this other control happens to be a ComboBox, this means that you must click twice to open it: Once to close the first drop-down, and a second time to open the 2nd drop-down. I hate to say it, but this behavior is *by design*. – Olivier Jacot-Descombes Dec 08 '18 at 17:11

2 Answers2

0

Thats not that easy.With basic .net you always need some kind of control / references to intercept clicks by binding click events. For Example if you have an MDI Parent (Mainwindow you can intercept its clicks).

Another way (using windows api) is to hook inso system events See the following stackoverflow post Global mouse event handler.

But you should think twice if you really need this.

Community
  • 1
  • 1
Boas Enkler
  • 12,264
  • 16
  • 69
  • 143
  • If I use this class i can detect mouse click, but has been detected always, i need get only outside click/ – Udjen Dec 30 '13 at 14:15
  • You can check wether your form is under the coordinates placed and / or if the click event of the form was also raised. As said this is a little fragile and you should test / and think about if this would be the clean solution – Boas Enkler Dec 30 '13 at 14:17
  • HEh, i think this solution is extreme measure)) – Udjen Dec 30 '13 at 14:20
0

In the form, you can pre-process messages sent to controls by using a message filter. Here is my FAILED attempt to implement the desired functionality:

public partial class frmAutoCloseDropDown : Form, IMessageFilter
{
    int _lastMsg;

    public frmAutoCloseDropDown()
    {
        InitializeComponent();
        Application.AddMessageFilter(this);
    }

    // THIS ATTEMPT DOES NOT WORK!
    public bool PreFilterMessage(ref Message m)
    {
        const int WM_LBUTTONDOWN = 0x0201;

        if (m.Msg!= _lastMsg) {
            _lastMsg = m.Msg;
        }
        if (m.Msg == WM_LBUTTONDOWN) {
            // You would have to do this recursively if the combo-boxes were nested inside other controls.
            foreach (ComboBox cbo in Controls.OfType<ComboBox>()) {
                cbo.DroppedDown = false;
            }
        }
        return false;
    }

    // Note: Dispose is created inside *.Designer.cs and you have to move it manually to *.cs
    protected override void Dispose(bool disposing)
    {
        if (disposing) {
            Application.RemoveMessageFilter(this);
            if (components != null) {
                components.Dispose();
            }
        }
        base.Dispose(disposing);
    }
}

Why does it not work? Probably because the new messages generated by cbo.DroppedDown = false that are sent to the form to close the drop-down are appended to the message queue and are only processed after the left mouse button click has been processed. This means that even when with PreFilterMessage our attempt to close the drop-down comes too late.

A possible solution would be to re-send WM_LBUTTONDOWN to the right ComboBox. You would have to interpret the parameters of the message to get the mouse coordinates and look to which combobox they are pointing to get its HWnd. My attempt to do this also shows that the behavior also depends on the drop-down style. It also has the undesired effect to close the drown-down you just opened. And what happens if you click in the drop-down itself to select an entry?

Probably you could do it, but the code tends to become very complicated. It's not worth the effort.

Olivier Jacot-Descombes
  • 104,806
  • 13
  • 138
  • 188