Reputation:
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.
Upvotes: 5
Views: 4499
Reputation: 6989
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.
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.
<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.
When you open your ComboBox like control, set this rectangle to Visible so that it can detect 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.
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.
Upvotes: 2
Reputation: 662
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:
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.
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):
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.
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.
Upvotes: 2