C# 用“弹出窗口”;StaysOpen=false";窃取LeftMouseButtonDown事件
在我的应用程序中,当用户试图单击主窗口上的滑块时,弹出控件处于打开状态,弹出控件将窃取鼠标按下事件。 这会导致滑块无法正确响应鼠标按下事件。 (它似乎获得了焦点并移动到了错误的位置) 我发现当弹出窗口的“StaysOpen”属性为false(并且弹出窗口是打开的)时,滑块中的“OnPreviewMouseLeftButtonDown”不会触发, 当其为真时(或当弹出窗口关闭时)会触发 我想知道是否有人找到了解决这个问题的方法 我在我的应用程序中的其他控件中遇到了这些类型的问题,因此我更喜欢更通用的解决方案,而不仅仅是解决滑块的问题 示例代码:C# 用“弹出窗口”;StaysOpen=false";窃取LeftMouseButtonDown事件,c#,wpf,xaml,popup,slider,C#,Wpf,Xaml,Popup,Slider,在我的应用程序中,当用户试图单击主窗口上的滑块时,弹出控件处于打开状态,弹出控件将窃取鼠标按下事件。 这会导致滑块无法正确响应鼠标按下事件。 (它似乎获得了焦点并移动到了错误的位置) 我发现当弹出窗口的“StaysOpen”属性为false(并且弹出窗口是打开的)时,滑块中的“OnPreviewMouseLeftButtonDown”不会触发, 当其为真时(或当弹出窗口关闭时)会触发 我想知道是否有人找到了解决这个问题的方法 我在我的应用程序中的其他控件中遇到了这些类型的问题,因此我更喜欢更通用
<Window x:Class="SampleApplication.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Name="Root"
Title="MainWindow" Height="350" Width="525">
<Grid Height="130" Width="300">
<Button Width="40" Height="40" Click="ButtonBase_OnClick" HorizontalAlignment="Left" VerticalAlignment="Top"></Button>
<Popup StaysOpen="False" IsOpen="{Binding ElementName=Root, Path=IsOpen}" Width="100" Height="100"
HorizontalAlignment="Center" VerticalAlignment="Center" Placement="Center">
<Grid Background="Black">
<TextBlock Text="hello"></TextBlock>
</Grid>
</Popup>
<Slider Width="200" IsMoveToPointEnabled="True" VerticalAlignment="Bottom"></Slider>
</Grid>
谢谢你,
Yotam发生这种情况是因为
PreviewMouseDown
(及其派生)(来自基类UIElement
)具有默认值
Direct-路由事件不通过元素树路由,但支持其他路由事件功能,如类处理、EventTrigger或EventSetter
这是从中获取的事件的源代码
下面是在这个过程中发生的事情:
因此,它就是这样设计的,您不应该使用OnPreviewMouseDown
来完成您在这里试图完成的任何任务
在我的应用程序中,当用户试图单击主窗口上的滑块时,弹出控件处于打开状态,弹出控件将窃取鼠标下降事件
虽然您的描述不完全正确,但这是任何
弹出控件的正常行为。出现这种情况的原因是弹出
控件具有焦点,因此它正在侦听单击
事件,即使该事件发生在弹出
的边界之外。现在从逻辑上考虑一下。。。如果它不这样做,它怎么知道何时关闭?您将在组合框中使用的弹出窗口
控件中发现相同的行为
要实现所需的行为,有一种解决方法,请为您使用的滑块控件设置“IshitteVisible=True”
PS:
仅当弹出窗口打开时,才将IshittesVisible设置为True,否则设置为False。我的最佳猜测是,如果要在单击其他内容时隐藏弹出窗口,则该弹出窗口有一个事件处理程序,无法正确路由事件。但是我也不知道如何解决这个问题。首先谢谢你的解释。我意识到弹出窗口需要捕捉那个事件,但是我希望有人能有一种技术来克服它带来的困难。也许有一种方法可以人为地将事件传递给其他人?我很乐意放弃使用OnPreviewLeftMouseDown,但是“Slider”控件,实际上相当多的标准WPF控件都会听它,结果会被弹出窗口破坏。我可以继续实现我自己版本的“Slider”和其他控件,我只是希望能够避免这种情况。据我所知(在快速谷歌搜索之后),不可能更改RoutedEvents
的行为。但是我不想实现一个自定义的滑块
,而是想实现一个自定义的弹出窗口
,因为这似乎是问题的根源,并且“覆盖”了事件/实现。也许你也可以尝试做一个AttachedEvent
,但这只是猜测,因为我到目前为止只在属性中使用了它。你是绝对正确的,在我的描述中,我试图强调我希望它发挥作用的方式。
public static readonly RoutedEvent PreviewMouseLeftButtonDownEvent =
EventManager.RegisterRoutedEvent(
"PreviewMouseLeftButtonDown",
RoutingStrategy.Direct,
typeof(MouseButtonEventHandler),
_typeofThis);
private void OnPreviewMouseButton(MouseButtonEventArgs e)
{
// We should only react to mouse buttons if we are in an auto close mode (where we have capture)
if (_cacheValid[(int)CacheBits.CaptureEngaged] && !StaysOpen)
{
Debug.Assert( Mouse.Captured == _popupRoot.Value, "_cacheValid[(int)CacheBits.CaptureEngaged] == true but Mouse.Captured != _popupRoot");
// If we got a mouse press/release and the mouse isn't on the popup (popup root), dismiss.
// When captured to subtree, source will be the captured element for events outside the popup.
if (_popupRoot.Value != null && e.OriginalSource == _popupRoot.Value)
{
// When we have capture we will get all mouse button up/down messages.
// We should close if the press was outside. The MouseButtonEventArgs don't tell whether we get this
// message because we have capture or if it was legit, so we have to do a hit test.
if (_popupRoot.Value.InputHitTest(e.GetPosition(_popupRoot.Value)) == null)
{
// The hit test didn't find any element; that means the click happened outside the popup.
SetCurrentValueInternal(IsOpenProperty, BooleanBoxes.FalseBox);
}
}
}
}