为什么当单击WPF Popup的背景区域时,它会关闭?

26

我有一个WPF Popup控件,其中包含一些编辑控件(列表框、文本框、复选框),并且它们之间有相当多的空白间隔。

Popup.StaysOpen被设置为False,这是必需的。如果用户在应用程序中的其他位置单击,则应将编辑操作视为已中止,并关闭弹出窗口。

不幸的是,每当用户单击弹出窗口的背景区域(即编辑控件之间的空白区域)时,弹出窗口也会关闭。

我尝试将弹出窗口设置为Focusable。我还尝试将弹出窗口的子元素(一个Border)设置为可聚焦。但两者都没有成功。

此外,鼠标事件似乎会穿过弹出窗口。当我单击弹出窗口下方的任何元素时,该元素就会获得焦点。这是尽管PopupBorder(我要点击的元素)的IsHitTestVisibleFocusable都设置为true

5个回答

42

最后,我发现以下方法有效。给定...

<Popup x:Name="_popup"
       StaysOpen="False"
       PopupAnimation="Slide"
       AllowsTransparency="True">

在调用InitializeComponent后,在构造函数中使用了这段代码...

// Ensure that any mouse event that gets through to the
// popup is considered handled, otherwise the popup would close
_popup.MouseDown += (s, e) => e.Handled = true;

1
太棒了!我甚至能够使用在Generic.xaml上定义的控件来完成它,通过使用EventToCommand,将EventArgs传递给命令,然后设置Handled=True。谢谢! - Dror
2
另一种将事件处理程序放入棘手位置的方法是派生一个从Popup派生的ArmouredPopup类。它可以重写OnMouseDown。我认为这是默认弹出窗口类中的一个错误。 - Adrian Ratnapala
1
我倾向于说这不是一个很好的解决方案,不是因为你提供的不好(实际上很好),而是因为开发人员不应该这样做。我已经玩弄这个问题很久了,看起来点击事件会传播到另一个事件处理程序,然后再次关闭弹出窗口。可能已经有一个MS Connect问题在处理中,希望MS团队发布修复。(@AdrianRatnapala同意) - Kieran Senior

7

它似乎很奇怪,它会忽略弹出窗口和边框上的Focusable。当鼠标移到边框上时,我通过更改触发器中的StaysOpen来解决您的问题:

<Grid xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <ToggleButton x:Name="btnPop" Content="Pop!" Width="100" Height="50"/>
    <Popup Placement="Bottom" PlacementTarget="{Binding ElementName=btnPop}" IsOpen="{Binding IsChecked, ElementName=btnPop}">
        <Popup.Style>
            <Style TargetType="{x:Type Popup}">
                <Setter Property="StaysOpen" Value="False"/>
                <Style.Triggers>
                    <DataTrigger Binding="{Binding IsMouseOver, ElementName=brd}" Value="True">
                        <Setter Property="StaysOpen" Value="True"/>
                    </DataTrigger>
                </Style.Triggers>
            </Style>
        </Popup.Style>
        <Border x:Name="brd" Background="White" BorderThickness="1" BorderBrush="Black">
            <StackPanel>
                <TextBox Margin="10"/>
                <TextBlock Text="Some text is here." Margin="10"/>
                <TextBox Margin="10"/>
            </StackPanel>            
        </Border>
    </Popup>
</Grid>

1
实际上,这对我很有效。@RobertMacnee,需要注意的一件事是,您应该确保不要在Popup元素本身上设置“StaysOpen”属性,否则它将无法正常工作,应该完全留给样式设置器和触发器。 - Kieran Senior

2

你的弹出窗口不是嵌套在ToggleButton或其他类型的按钮中吗?那么在Popup级别停止路由事件是让它正常工作的逻辑。


1

我最好的猜测是你遇到了一些透明度问题。尝试在弹出窗口上设置一个背景画刷。


感谢您的回答。边框控件填充整个弹出窗口的区域,并设置了实心画刷。 - Drew Noakes

-1

你可以设置 StayOpen=true,并在弹出窗口的 MouseLeave 事件中设置一个计时器 timer.Start(),例如在 3 秒后关闭此弹出窗口,在 MouseEnter 事件中停止计时器 timer.Stop()。这样就可以实现了。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接