I now read many threads and tried and so on. I don't get it.
Question When using MouseCapture any other control isn't motioned. Cannot click something. No Highlightings happens on mouse over. MouseCaption is blocking that. Clicking Twice is necessary. How to avoid that?
Basically I created a custom autocompletebox which consists of a textbox for free input and a dropdown as textblock containing suggested result-element by the given input. This is pretty like a standard ComboBox.
From Combobox we know, when it is expanded and one clicks somewhere else the dropdown is collapsed.
I want exactly the same behavior like the combobox uses.
Because I am not the first one asking that, I tried several things but didn't get them fully working.
What I still tried and I failed with.
- Adding
OnLostFocus
event to the textbox does not recognize any mouse clicks to non-focusable Elements. - Using
Mous.Caption(this)
withPreviewMouseLeftButtonDown
to receive any mouse clicks on any place on the window.- Yeah that works! I can collapse my dropdown, Un-Capture the mouse again.
- But: The mouse caption prevents me from clicking to other UIElement. Checkboxes and RadioBoxes wont be toggled. Just hovering the mouse over a Checkbox or anything else is not highlighting that element any more. Instead I now need to click twice to check a textbox.
- I can't figure out, how to solve that.
- Also what did not work was that when the mouse-capture event was fired, I cannot figure out where the click has been made.
source
as well ase.OriginalSource
are equal to my custom control- Getting the Mouse-Position may be an option. But did not find to get the position of my control related to the mouse-position. any properties on the control return NaN.
- At first I was not able to recognize any difference between
PreviewMouseLeftButtonDown
andMouseLeftButtonDown
.- I thought the first one, when directly releasing mouse-capture, would fire the mouseclick event to its original destination without the mouse capture any more. It doesn't.
- I got it by using the Hittest. Is it that way to do so?
Some Code
XAML of AutoCompleteBox
<UserControl x:Class="MyProject.Wpf.Application.Control.AutoCompleteBoxControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Name="AutoCompleteBox"
PreviewMouseLeftButtonDown="AutoComplete_MouseLeftButtonDown">
<Grid>
<StackPanel>
<TextBox Name="AutoCompleteTextBox" Text="{Binding ElementName=AutoCompleteBox, Path=TextBoxText, Mode=TwoWay}" Height="{Binding ElementName=AutoCompleteBox, Path=TextBoxHeight}" Width="{Binding ElementName=AutoCompleteBox, Path=TextBoxWidth}" Padding="5, 3, 5, 3" KeyUp="AutoCompleteTextBoxControl_KeyUp" LostKeyboardFocus="AutoCompleteTextBox_OnLostKeyboardFocus"/>
<Popup Name="ResultStackPopup" IsOpen="True" PlacementTarget="{Binding ElementName=AutoCompleteTextBox}" Placement="Custom">
<Border Name="ResultStackBorder" Width="{Binding ElementName=AutoCompleteBox, Path=SuggestionListWidth}" Height="{Binding ElementName=AutoCompleteBox, Path=SuggestionListHeight}" BorderBrush="Black" BorderThickness="1" Visibility="Collapsed" Background="White" Margin="1,0,1,0" HorizontalAlignment="Left">
<ScrollViewer VerticalScrollBarVisibility="Auto">
<StackPanel Name="ResultStack"></StackPanel>
</ScrollViewer>
</Border>
</Popup>
</StackPanel>
</Grid>
</UserControl>
relevant code behind:
//Whenever the dropdown is expanded, the mouse caption is started:
this.CaptureMouse();
mouse-down event:
private void AutoComplete_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
if (this.IsMouseCaptured)
{
if (!this.IsMouseInBounds())
{
//Release MouseCaption
this.ReleaseMouseCapture();
//Collapse SuggestionList
var border = (this.ResultStack.Parent as ScrollViewer)?.Parent as Border;
if (border != null)
{
border.Visibility = Visibility.Collapsed;
}
}
}
}
private bool IsMouseInBounds()
{
Point point = Mouse.GetPosition(this);
// Perform the hit test against a given portion of the visual object tree.
HitTestResult result = VisualTreeHelper.HitTest(this, point);
if (result != null)
{
return true;
}
return false;
}
Edit
Unfortunately the Popup is (afaik) not a member of the visualTree. So the hittest for the Popup does not work. So I tried to get the position of the Popup to check with the Mouse-position.
The TransformToAncestor method is to be used as everyone is saying that. But this does not seem to work properly:
The following three calls do return exactly the same points:
Window parentWindow = Window.GetWindow(this);
Point relativePointThis = this.TransformToAncestor(parentWindow).Transform(new Point(0, 0));
Point relativePointPopup = this.ResultStackPopup.TransformToAncestor(parentWindow).Transform(new Point(0, 0));
Point relativePointBorder = this.ResultStackBorder.TransformToAncestor(parentWindow).Transform(new Point(0, 0));
Is this a bug?