WPF ComboBox:点击弹出窗口外部抑制鼠标单击

4

我使用标准的WPF ComboBox控件。当弹出窗口打开时,如果用户在外部点击了其他地方,弹出窗口会关闭。但是,如果窗口上有按钮并且用户单击该按钮(弹出窗口仍然打开),则按钮的单击处理程序不会执行。弹出窗口被关闭,但是用户必须再次单击按钮才能触发单击事件。

我知道这是该控件的标准行为。您有任何想法如何绕过此行为吗?谢谢!


对我来说不是这样的。弹出窗口关闭后,按钮点击事件才会被触发。 - AnjumSKhan
你使用WPF吗?标准控件?你的.NET框架版本是多少? - andrei.aliashkevich
4个回答

2
我和 @Eng. M.Hamdy 采用了非常好的方法 修复了一些错误,并使用 C# 应用到所有组合框中。
应用钩子:
EventManager.RegisterClassHandler(typeof(ComboBox), UIElement.PreviewMouseLeftButtonDownEvent, new MouseButtonEventHandler(FixComboBoxOutClick));

处理程序代码:
    private void FixComboBoxOutClick(object sender, MouseButtonEventArgs e) {
        if (sender is ComboBox combo) {
            Point comboRelativePoint = Mouse.GetPosition(combo);
            if (comboRelativePoint.X < 0 || comboRelativePoint.Y < 0 || comboRelativePoint.X > combo.ActualWidth || comboRelativePoint.Y > combo.ActualHeight) {
                UIElement popupContent = combo.FindChild<Popup>(null).Child;
                Point popupRelativePoint = Mouse.GetPosition(popupContent);
                if (popupRelativePoint.X < 0 || popupRelativePoint.Y < 0 || popupRelativePoint.X > popupContent.RenderSize.Width || popupRelativePoint.Y > popupContent.RenderSize.Height) {
                    combo.IsDropDownOpen = false;
                }
            }
        }
    }

您可以在这里查找FindChild<T>()的实现。

1
我使用了一个简单的解决方案: 在PreviewMouseLeftButtonDown事件中,如果鼠标位置在组合框外面,则关闭下拉菜单。这将允许其他控件获取鼠标点击:
Dim p = Mouse.GetPosition(combo)
If p.X < 0 OrElse p.Y < 0 OrElse p.X > combo.Width OrElse p.Y > combo.Height Then
     cmb.IsDropDownOpen = False
End If

1
你可以为ComboBox的DropDownClosed事件创建一个事件,并使用hittest函数找到用户单击的其他控件。
private void ComboBox_DropDownClosed(object sender, EventArgs e)
{
    Point m = Mouse.GetPosition(this);
    VisualTreeHelper.HitTest(this, this.FilterCallback, this.ResultCallback, new PointHitTestParameters(m));
}

private HitTestFilterBehavior FilterCallback(DependencyObject o)
{
    var c = o as Control;
    if ((c != null) && !(o is MainWindow))
    {
        if (c.Focusable)
        {
            if (c is ComboBox)
            {
                (c as ComboBox).IsDropDownOpen = true;
            }
            else
            {
                var mouseDevice = Mouse.PrimaryDevice;
                var mouseButtonEventArgs = new MouseButtonEventArgs(mouseDevice, 0, MouseButton.Left)
                {
                    RoutedEvent = Mouse.MouseDownEvent,
                    Source = c
                };
                c.RaiseEvent(mouseButtonEventArgs);
            }

            return HitTestFilterBehavior.Stop;
        }
    }
    return HitTestFilterBehavior.Continue;
}

private HitTestResultBehavior ResultCallback(HitTestResult r)
{
    return HitTestResultBehavior.Continue;
}

在FilterCallback函数中找到控件后,在该控件上触发鼠标按下事件。

我发现触发事件对于组合框不起作用,所以对于单击它,我只需将IsDropDownOpen设置为true。

我在这里找到了代码并进行了一些修改。


-1
你可以尝试在 ComboBox 获取到鼠标捕获后立即释放它: 在 XAML 中的 ComboBox 属性中:
GotMouseCapture="ComboBox_OnGotMouseCapture"

在代码后台:

private void ComboBox_OnGotMouseCapture(object sender, MouseEventArgs e)
{
    ComboBox.ReleaseMouseCapture();
}

这将阻止下拉菜单的展开。 - Muhannad

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接