在 WPF 中,使用 Popup 也许会看到 PreviewMouseDown 事件被吃掉
因为 PreviewMouseDown 是 RoutingStrategy.Direct 路由事件,不能在多个视觉树使用,在设置 Popup 点击界面 StaysOpen=“False” 的逻辑就在下面代码
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); } } }}
如果写一个 CheckBox 放在界面上,运行代码可以看到可以被打勾但是没有事件
<Grid> <StackPanel> <Button Margin="10,10,10,10" Content="Open Popup" Click="OpenPopup_OnClick"></Button> <CheckBox PreviewMouseDown="UIElement_OnPreviewMouseDown"></CheckBox> </StackPanel> <Popup x:Name="Popup" StaysOpen="False"> <Grid Width="100" Height="100" Background="White"> <TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" Text="Popup"></TextBlock> </Grid> </Popup></Grid>
在 UIElement_OnPreviewMouseDown
添加输出内容,代码如下,可以看到,没有符合预期输出
private void UIElement_OnPreviewMouseDown(object sender, MouseButtonEventArgs e){ Debug.WriteLine("PreviewMouseDown");}
private void OpenPopup_OnClick(object sender, RoutedEventArgs e){ Popup.PlacementTarget = (UIElement) sender; Popup.Placement = PlacementMode.Mouse; Popup.IsOpen = true;}
本文代码放在 github 欢迎访问
此问题已报告 WPF 官方,请看 Known issus: Popup with “StaysOpen=false” steals PreviewMouseDown event · Issue #2166 · dotnet/wpf
更多请看 dotnet 读 WPF 源代码 Popup 的 StaysOpen 为 false 将会吃掉其他窗口的首次激活

本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。 欢迎转载、使用、重新发布,但务必保留文章署名 林德熙 (包含链接: https://blog.lindexi.com ),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。如有任何疑问,请与我 联系。