我现在阅读了很多线程并尝试了等等。我不明白。
问题 使用 MouseCapture 时,任何其他控件都没有动作。无法单击某些内容。鼠标悬停时没有突出显示。MouseCaption 阻止了这一点。单击两次是必要的。如何避免这种情况?
基本上 ,我创建了一个自定义自动完成框,它由一个用于自由输入的文本框和一个作为文本块的下拉列表组成,其中包含给定输入的建议结果元素。这很像一个标准的组合框。
从 Combobox 我们知道,当它展开并单击其他地方时,下拉列表会折叠。
我想要与组合框使用的完全相同的行为。
因为我不是第一个这样问的人,所以我尝试了几件事,但没有让它们完全正常工作。
我仍然尝试过但失败了。
- 向文本框添加
OnLostFocus
事件无法识别对不可聚焦元素的任何鼠标单击。 - 使用
Mous.Caption(this)
withPreviewMouseLeftButtonDown
接收在窗口上任何位置的任何鼠标点击。- 是的,这行得通!我可以折叠我的下拉菜单,再次取消捕获鼠标。
- 但是:鼠标标题阻止我点击其他 UIElement。复选框和 RadioBoxes 不会被切换。只需将鼠标悬停在复选框或其他任何内容上,就不会再突出显示该元素。相反,我现在需要单击两次以检查文本框。
- 我想不通,如何解决。
- 还有什么不起作用的是,当鼠标捕获事件被触发时,我无法弄清楚点击是在哪里进行的。
source
以及e.OriginalSource
等于我的自定义控件- 获取鼠标位置可能是一种选择。但是没有找到我的控件与鼠标位置相关的位置。控件上的任何属性都返回 NaN。
- 起初我无法识别
PreviewMouseLeftButtonDown
和之间的任何区别MouseLeftButtonDown
。- 我认为第一个,当直接释放鼠标捕获时,会将 mouseclick 事件触发到其原始目标,而不再捕获鼠标。它没有。
- 我是通过使用 Hittest 得到的。是这样吗?
一些代码
自动完成框的 XAML
<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>
后面的相关代码:
//Whenever the dropdown is expanded, the mouse caption is started:
this.CaptureMouse();
鼠标按下事件:
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;
}
编辑
不幸的是,弹出窗口(afaik)不是visualTree的成员。所以 Popup 的 hittest 不起作用。所以我试图让弹出窗口的位置来检查鼠标位置。
正如大家所说,TransformToAncestor 方法将被使用。但这似乎无法正常工作:
以下三个调用确实返回完全相同的点:
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));
这是一个错误吗?