【问题标题】:WPF ComboBox: click outside of popup suppress mouse clickWPF ComboBox:在弹出窗口之外单击抑制鼠标单击
【发布时间】:2016-06-17 23:25:12
【问题描述】:

我使用标准的 WPF ComboBox 控件。当弹出窗口打开并且用户单击外部某处时,弹出窗口将关闭。但是如果窗口上有按钮并且用户点击它(弹出窗口仍然打开),则不会执行按钮的点击处理程序。弹出窗口已关闭,但用户必须再单击一次按钮才能引发点击事件。

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

【问题讨论】:

  • 对我来说并非如此。关闭 Popup 后引发按钮单击事件。
  • 您使用 WPF?标准控制?您的 .net 框架版本是什么?

标签: c# wpf combobox behavior dropdown


【解决方案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 函数中找到该控件后,在该控件上引发鼠标按下事件。

我发现了 raise 事件,在组合框上不起作用,所以点击它,我只需将 IsDropDownOpen 设置为 true。

我在here找到了代码并稍作修改。

【讨论】:

    【解决方案2】:

    我用@Eng 修复了一些错误。 M.Hamdy very good approach 并在 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&lt;T&gt;() 实现here

    【讨论】:

      【解决方案3】:

      我使用了一个简单的解决方案: 在 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
      

      【讨论】:

        【解决方案4】:

        您可以尝试在 ComboBox 获得一个后立即释放鼠标捕获: 在 XAML 中的 ComboBox 属性中:

        GotMouseCapture="ComboBox_OnGotMouseCapture"
        

        在代码隐藏中:

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

        【讨论】:

        • 这将停止下拉菜单
        猜你喜欢
        • 2012-12-21
        • 2022-12-31
        • 1970-01-01
        • 2023-02-09
        • 2010-12-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-08-20
        相关资源
        最近更新 更多