Reputation: 93
I use a standard WPF ComboBox control. When popup is opened and user clicks somewhere outside, popup is closed. But if there is button on the window and user clicks on it (with popup still opened), button's click handler is not executed. Popup is closed, but user has to click one more time on the button to raise click event on it.
I know that is standard behavior for this control. Have you any ideas how to bypass this behavior? Thanks!
Upvotes: 4
Views: 2894
Reputation: 532
I fixed some bugs with @Eng. M.Hamdy very good approach and did it in C#, also applying it to all comboboxes application wide.
Application hook:
EventManager.RegisterClassHandler(typeof(ComboBox), UIElement.PreviewMouseLeftButtonDownEvent, new MouseButtonEventHandler(FixComboBoxOutClick));
Handler code:
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;
}
}
}
}
You can look for FindChild<T>()
implementations here.
Upvotes: 2
Reputation: 314
I used an easy solution: In the PreviewMouseLeftButtonDown event, if the mouse pos is outside the combobox, close the dropdown. This will allow other control to get the mouse click:
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
Upvotes: 1
Reputation: 1010
You can create an event for ComboBox DropDownClosed and with the hittestfunction, find the other control that the user has clicked.
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;
}
Then in the FilterCallback function after finding that control, raise the mouse down event on that control.
I found the raise event, does not work on comboboxes so for clicking that, I simply set the IsDropDownOpen to true.
I found the code in here and modified it a little.
Upvotes: 1
Reputation: 151
You can try to release the mouse capture right after the ComboBox gets one: In your's ComboBox properties in XAML:
GotMouseCapture="ComboBox_OnGotMouseCapture"
And in code-behind:
private void ComboBox_OnGotMouseCapture(object sender, MouseEventArgs e)
{
ComboBox.ReleaseMouseCapture();
}
Upvotes: -1