WinForms控件';s的子窗体没有';控件处于模式对话框时,不响应鼠标事件

本文关键字:控件 对话框 模式 鼠标 事件 不响应 窗体 于模式 WinForms | 更新日期: 2023-09-27 18:29:51

我需要标准组合框中不存在的功能,所以我从一个TextBox和一个表单中编写了自己的功能。当用户在TextBox中键入时,它会显示一个单独表单的下拉列表。

以下是一些相关代码:

internal class FilteredDropDown : Form
{
    public Control OwnerControl { get; set; }
    public bool CloseOnLostFocus { get; set; }
    protected override OnLostFocus(EventArgs e)
    {
        if (CloseOnLostFocus && !OwnerControl.IsFocused)
            this.Close();
    }
    protected override OnMouseMove(MouseEventArgs e)
    {
        base.OnMouseMove(e)
         // highlight the moused over item in the list
    }
    ...
}
public class FilteredCombo : TextBox
{
    private FilteredDropDown dropDown;
    public FilteredCombo()
    {
        dropDown = new FilteredDropDown();
        dropDown.OwnerControl = this;
    }
    public void ShowDropDown()
    {
        if (dropDown.Visible)
            return;
        dropDown.RefreshFilter();
        var loc = PointToScreen(new Point(0, this.Height));
        dropDown.Location = loc;
        dropDown.CloseOnLostFocus = false;
        int selectionStart = this.SelectionStart;
        int selectionLength = this.SelectionLength;
        dropDown.Show(this);
        this.Focus();
        this.SelectionStart = selectionStart;
        this.SelectionLength = selectionLength;
        dropDown.CloseOnLostFocus = false;
    }
    protected override OnLostFocus(EventArgs e)
    {
        if (dropDown.Visible && !dropDown.ContainsFocus())
            dropDown.Close();
    }
    protected override OnTextChanged(EventArgs e)
    {
        base.OnTextChanged(e);
        ShowDropDown();
    }
    ...
}

显然还有更多的代码来处理与我的问题无关的各种东西。

问题是当我把FilteredCombo放在模式对话框上时。当FilteredDropDown窗体被模式对话框作为父窗体时,它根本不会接收鼠标事件。

我读过一些关于WinForms过滤掉除当前模态对话框之外的所有事件的文章,我怀疑这就是发生的事情,但我不知道如何修复它。有没有办法让鼠标上下移动/点击等。以模型对话框为父对象时要工作的事件?

WinForms控件';s的子窗体没有';控件处于模式对话框时,不响应鼠标事件

我不得不深入研究ShowDialog源代码,发现它在除显示的窗口外的所有窗口上都调用user32.dll EnableWindow(Handle,false)。问题是在调用ShowDialog()方法时FilteredDropDown已经存在。我发现了两种不同的方法来解决这个问题:

  1. 在显示父窗体之前,不允许显示下拉列表。这有点难以保证,所以我也实现了第二种方式。

  2. 当下拉窗口可见时重新启用:

    [DllImport("user32.dll")]
    private static extern bool EnableWindow(IntPtr hWnd, bool enable);
    protected override void OnVisibleChanged(EventArg e)
    {
        base.OnVisibleChanged(e);
        if (this.Visible)
        {
            EnableWindow(this.Handle, true);
        }
    }