WPF - Combobox如何知道何时关闭下拉菜单

时间:2022-05-17 22:58:32

I want to write a control similar to ComboBox and I'm wondering if anybody knows how to detect when a user clicks outside the ComboBox boundaries. The ComboBox closes it's dropdown in this situation.

我想写一个类似于ComboBox的控件,我想知道是否有人知道如何检测用户在ComboBox边界外点击的时间。在这种情况下,ComboBox会关闭它的下拉列表。

2 个解决方案

#1


2  

You can define your own custom control and control template with a textbox and a popup. Then override the OnApplyTemplate method of your control and find the popup using:

您可以使用文本框和弹出窗口定义自己的自定义控件和控件模板。然后覆盖控件的OnApplyTemplate方法并使用以下命令查找弹出窗口:

var popup = this.GetTemplateChild("PART_Popup") as Popup;

Now you can decide when to display or hide the popup by setting its IsOpen properties to true or false.

现在,您可以通过将其IsOpen属性设置为true或false来决定何时显示或隐藏弹出窗口。

To find out if a user clicks on some other part of you UI just subscribe to the PreviewMouseDown event on your control's parent (somewhere in your control initialization code):

要确定用户是否点击了您的其他部分UI,只需在控件的父级(控件初始化代码中的某个位置)上订阅PreviewMouseDown事件:

var parent = VisualTreeHelper.GetParent(this) as UIElement;
if(parent != null) {
    parent.PreviewMouseDown += MouseDownHandler;
}

Now you should get notified whenever a user clicks anywhere inside your control's container. You can also use the VisualTreeHelper.GetParent(...) recursively to get to the root element (such as a window) until it returns a null.

现在,只要用户点击控件容器内的任何位置,您就会收到通知。您还可以递归地使用VisualTreeHelper.GetParent(...)来获取根元素(例如窗口),直到它返回null。

The popup will not be in the same visual tree and therefore you need to define mouse event handlers for the popup's root element if you want to know when a user clicks inside the popup.

弹出窗口不在同一个可视树中,因此如果您想知道用户何时在弹出窗口内单击,您需要为弹出窗口的根元素定义鼠标事件处理程序。

#2


2  

I had the same question many years ago with an early version of Silverlight. I examined the control template and decompiled the Microsoft code to find that they were using an invisible overlay across the entire window to detect clicks. The WPF comboBox does not seem to work the same way, but you can follow the Silverlight pattern.

很多年前,我在早期版本的Silverlight中遇到了同样的问题。我检查了控件模板并反编译了Microsoft代码,发现他们在整个窗口中使用了一个不可见的叠加来检测点击。 WPF comboBox似乎没有相同的工作方式,但您可以遵循Silverlight模式。

You'll want to create a rectangle that is the same size as your window. I do this by using a RowSpan to cover the primary Grid that holds my entire application. You could also bind the Height/Width to the Window Height/Width. There are a dozen ways to do it, just get it to fill your entire Window. Give the rectangle a fill color of White and an Opacity of 0. It does need a Fill color to work, however with Opacity=0 the user will not see it. For debugging purposes you might give it Red and Opacity .25.

您需要创建一个与窗口大小相同的矩形。我这样做是通过使用RowSpan来覆盖保存整个应用程序的主Grid。您还可以将高度/宽度绑定到窗口高度/宽度。有十几种方法可以做到这一点,只需要让它填满你的整个窗口。为矩形提供填充颜色为白色且不透明度为0.它确实需要填充颜色才能工作,但是如果Opacity = 0,则用户将看不到它。出于调试目的,您可以将其赋予红色和不透明度.25。

<Rectangle x:Name="fullScreenOverlay" Grid.RowSpan="3" Opacity="0" Fill="White" Visibility="Collapsed" MouseDown="FullScreenOverlay_OnMouseDown" />

A key part of this is to put the Rectangle at the bottom of your XAML so that it renders on top of any other XAML controls.

其中一个关键部分是将Rectangle放在XAML的底部,以便它呈现在任何其他XAML控件之上。

When you open your ComboBox like control, set this rectangle to Visible so that it can detect clicks/MouseDown.

当您打开类似控件的ComboBox时,将此矩形设置为Visible,以便它可以检测到clicks / MouseDown。

private void NotificationButton_Click(object sender, RoutedEventArgs e)
{
    fullScreenOverlay.Visibility = Visibility.Visible;
    notificationPopup.Visibility = Visibility.Visible;
}

When you detect a click, set the Rectangle back to collapsed and close your ComboBox like popup. All done.

当您检测到单击时,将矩形设置回折叠并关闭ComboBox,如弹出窗口。全做完了。

private void FullScreenOverlay_OnMouseDown(object sender, MouseButtonEventArgs e)
{
    fullScreenOverlay.Visibility = Visibility.Collapsed;
    notificationPopup.Visibility = Visibility.Collapsed;
}

This will not detect clicks that occur outside of your application as the Microsoft ComboBox does. It will only detect clicks inside the application. But frankly, I prefer it that way anyway.

这不会像Microsoft ComboBox那样检测应用程序外部发生的点击。它只会检测应用程序内的点击次数。但坦率地说,无论如何我更喜欢这样。

#1


2  

You can define your own custom control and control template with a textbox and a popup. Then override the OnApplyTemplate method of your control and find the popup using:

您可以使用文本框和弹出窗口定义自己的自定义控件和控件模板。然后覆盖控件的OnApplyTemplate方法并使用以下命令查找弹出窗口:

var popup = this.GetTemplateChild("PART_Popup") as Popup;

Now you can decide when to display or hide the popup by setting its IsOpen properties to true or false.

现在,您可以通过将其IsOpen属性设置为true或false来决定何时显示或隐藏弹出窗口。

To find out if a user clicks on some other part of you UI just subscribe to the PreviewMouseDown event on your control's parent (somewhere in your control initialization code):

要确定用户是否点击了您的其他部分UI,只需在控件的父级(控件初始化代码中的某个位置)上订阅PreviewMouseDown事件:

var parent = VisualTreeHelper.GetParent(this) as UIElement;
if(parent != null) {
    parent.PreviewMouseDown += MouseDownHandler;
}

Now you should get notified whenever a user clicks anywhere inside your control's container. You can also use the VisualTreeHelper.GetParent(...) recursively to get to the root element (such as a window) until it returns a null.

现在,只要用户点击控件容器内的任何位置,您就会收到通知。您还可以递归地使用VisualTreeHelper.GetParent(...)来获取根元素(例如窗口),直到它返回null。

The popup will not be in the same visual tree and therefore you need to define mouse event handlers for the popup's root element if you want to know when a user clicks inside the popup.

弹出窗口不在同一个可视树中,因此如果您想知道用户何时在弹出窗口内单击,您需要为弹出窗口的根元素定义鼠标事件处理程序。

#2


2  

I had the same question many years ago with an early version of Silverlight. I examined the control template and decompiled the Microsoft code to find that they were using an invisible overlay across the entire window to detect clicks. The WPF comboBox does not seem to work the same way, but you can follow the Silverlight pattern.

很多年前,我在早期版本的Silverlight中遇到了同样的问题。我检查了控件模板并反编译了Microsoft代码,发现他们在整个窗口中使用了一个不可见的叠加来检测点击。 WPF comboBox似乎没有相同的工作方式,但您可以遵循Silverlight模式。

You'll want to create a rectangle that is the same size as your window. I do this by using a RowSpan to cover the primary Grid that holds my entire application. You could also bind the Height/Width to the Window Height/Width. There are a dozen ways to do it, just get it to fill your entire Window. Give the rectangle a fill color of White and an Opacity of 0. It does need a Fill color to work, however with Opacity=0 the user will not see it. For debugging purposes you might give it Red and Opacity .25.

您需要创建一个与窗口大小相同的矩形。我这样做是通过使用RowSpan来覆盖保存整个应用程序的主Grid。您还可以将高度/宽度绑定到窗口高度/宽度。有十几种方法可以做到这一点,只需要让它填满你的整个窗口。为矩形提供填充颜色为白色且不透明度为0.它确实需要填充颜色才能工作,但是如果Opacity = 0,则用户将看不到它。出于调试目的,您可以将其赋予红色和不透明度.25。

<Rectangle x:Name="fullScreenOverlay" Grid.RowSpan="3" Opacity="0" Fill="White" Visibility="Collapsed" MouseDown="FullScreenOverlay_OnMouseDown" />

A key part of this is to put the Rectangle at the bottom of your XAML so that it renders on top of any other XAML controls.

其中一个关键部分是将Rectangle放在XAML的底部,以便它呈现在任何其他XAML控件之上。

When you open your ComboBox like control, set this rectangle to Visible so that it can detect clicks/MouseDown.

当您打开类似控件的ComboBox时,将此矩形设置为Visible,以便它可以检测到clicks / MouseDown。

private void NotificationButton_Click(object sender, RoutedEventArgs e)
{
    fullScreenOverlay.Visibility = Visibility.Visible;
    notificationPopup.Visibility = Visibility.Visible;
}

When you detect a click, set the Rectangle back to collapsed and close your ComboBox like popup. All done.

当您检测到单击时,将矩形设置回折叠并关闭ComboBox,如弹出窗口。全做完了。

private void FullScreenOverlay_OnMouseDown(object sender, MouseButtonEventArgs e)
{
    fullScreenOverlay.Visibility = Visibility.Collapsed;
    notificationPopup.Visibility = Visibility.Collapsed;
}

This will not detect clicks that occur outside of your application as the Microsoft ComboBox does. It will only detect clicks inside the application. But frankly, I prefer it that way anyway.

这不会像Microsoft ComboBox那样检测应用程序外部发生的点击。它只会检测应用程序内的点击次数。但坦率地说,无论如何我更喜欢这样。