如何在C#中检测winform控件外的鼠标点击

时间:2013-12-30 13:47:37

标签: c# .net winforms mouseevent mouseclick-event

我有一个自定义控件(自​​定义ComboBox)。它工作得很好,当我按下“箭头按钮”它部署,如果我再按它它也部署,但如果它已部署,我按我的形式任何地方 - 它关闭但是,当我试图打开它 - 我必须按两次“箭头按钮”。所以当我点击我的组合框外面时,我需要检测这个时刻。

打开ComboBox的代码(在ButtonClick中调用)

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

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

关闭事件

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

所以,我想要这样的东西

private ClickedOutsideControl()
{
    dropflag = true;
}

2 个答案:

答案 0 :(得分:0)

不是那么容易。使用基本的.net,你总是需要通过绑定点击事件来拦截点击来控制/引用。例如,如果你有一个MDI Parent(Mainwindow,你可以拦截它的点击次数)。

另一种方法(使用windows api)是挂钩inso系统事件请参阅以下stackoverflow帖子Global mouse event handler

但如果你真的需要这个,你应该三思而行。

答案 1 :(得分:0)

在表单中,您可以使用消息过滤器预处理发送到控件的消息。这是我失败的尝试,以实现所需的功能:

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

为什么不起作用?可能是因为cbo.DroppedDown = false生成的发送到表单以关闭下拉列表的新消息被附加到消息队列中,并且仅在鼠标左键单击处理后 。这意味着即使使用PreFilterMessage来关闭下拉菜单,也来不及了。

可能的解决方案是将WM_LBUTTONDOWN重新发送到右侧的ComboBox。您将必须解释消息的参数以获取鼠标坐标,并查看它们所指向的组合框以获取其HWnd。我这样做的尝试还表明,行为也取决于下拉样式。它还具有关闭刚打开的溺水的不良效果。如果您单击下拉列表本身来选择一个条目,会发生什么?

也许您可以做到,但是代码往往变得非常复杂。这不值得付出努力。