C# 用“弹出窗口”;StaysOpen=false";窃取LeftMouseButtonDown事件

C# 用“弹出窗口”;StaysOpen=false";窃取LeftMouseButtonDown事件,c#,wpf,xaml,popup,slider,C#,Wpf,Xaml,Popup,Slider,在我的应用程序中,当用户试图单击主窗口上的滑块时,弹出控件处于打开状态,弹出控件将窃取鼠标按下事件。 这会导致滑块无法正确响应鼠标按下事件。 (它似乎获得了焦点并移动到了错误的位置) 我发现当弹出窗口的“StaysOpen”属性为false(并且弹出窗口是打开的)时,滑块中的“OnPreviewMouseLeftButtonDown”不会触发, 当其为真时(或当弹出窗口关闭时)会触发 我想知道是否有人找到了解决这个问题的方法 我在我的应用程序中的其他控件中遇到了这些类型的问题,因此我更喜欢更通用

在我的应用程序中,当用户试图单击主窗口上的滑块时,弹出控件处于打开状态,弹出控件将窃取鼠标按下事件。 这会导致滑块无法正确响应鼠标按下事件。 (它似乎获得了焦点并移动到了错误的位置)

我发现当弹出窗口的“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);
            }
        }
    }
}