即使使用 StaysOpen="false",WPF 弹出窗口也不会关闭

WPF popup wont close even with StaysOpen="false"

我正在努力实现以下目标:

  1. 用户在数据网格中调出上下文菜单。
  2. 用户选择一个上下文菜单项,然后打开一个弹出窗口并显示一些信息。
  3. 当用户单击应用程序中的其他任何地方而不是弹出窗口时,弹出窗口将关闭。

在我关闭弹出窗口之前一切正常。

从别处搜索我知道我需要将 Staysopen 设置为 false(它是) 我还读到最好的方法是将 IsOpen 值绑定到视图模型中的 属性 并将其绑定设置为 2 方式(也已完成)

作为旁注,我发现如果我添加一个文本框并在框内单击,然后当我在弹出窗口外单击时,它会根据需要关闭。

作为解决方法,我尝试过的另一件事没有成功,是以编程方式将键盘焦点设置在文本框上以获得我想要的 "autoclose" 功能。

代码如下:

xaml -

<Popup Name="PredictionsPopup" Height="200" Width="200" AllowsTransparency="false" StaysOpen="False" IsOpen="{Binding DisplaySummaryPopup, Mode=TwoWay}">
            <StackPanel Background="{DynamicResource {x:Static SystemColors.ControlBrushKey}}">
                <TextBlock Text="here is some stuff" />
                <TextBox Name="hiddenBox" Text="moo"/>
            </StackPanel>         
        </Popup>

选择菜单项时在视图模型上设置 属性 的代码隐藏。

 private void CurrentPredicitions_OnClick(object sender, RadRoutedEventArgs e)
        {

            PredictionsPopup.Placement = PlacementMode.MousePoint;
            ViewModel.DisplaySummaryPopup = true;

        }

视图模型属性

public bool? DisplaySummaryPopup
        {
            get
            {
                return this.displaySummaryPopup;
            }

            set
            {
                this.displaySummaryPopup = value;
                RaisePropertyChanged(() => this.DisplaySummaryPopup);
            }
        }

如果您需要更多详细信息,请告诉我。

这里有一个工作示例:

主窗口XAML:

<Window x:Class="WpfApplication2.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <Popup Name="PredictionsPopup" Height="200" Width="200" AllowsTransparency="false" StaysOpen="False" IsOpen="{Binding DisplaySummaryPopup, Mode=TwoWay}">
            <StackPanel Background="Red">
                <TextBlock Text="here is some stuff" />
                <TextBox Name="hiddenBox" Text="moo"/>
            </StackPanel>
        </Popup>
        <DataGrid AutoGenerateColumns="False"  Name="dataGrid1"  IsReadOnly="True" >
            <DataGrid.Columns>
                <DataGridTextColumn Header="Site"  Width="150" />
                <DataGridTextColumn Header="Subject"  Width="310" />
            </DataGrid.Columns>
            <DataGrid.ContextMenu>
                <ContextMenu>
                    <MenuItem Header="Click Me" Click="ButtonBase_OnClick">                     
                    </MenuItem>
                </ContextMenu>
            </DataGrid.ContextMenu>
        </DataGrid>
      

    </Grid>
</Window>

主窗口坐标:

 public MainWindow()
        {
            InitializeComponent();
            DataContext = new TestViewModel();
        }

        private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
        {
            PredictionsPopup.Placement = PlacementMode.MousePoint;
            PredictionsPopup.IsOpen = true;

        }

视图模型:

  public class TestViewModel : INotifyPropertyChanged
    {
        private bool _displaySumarry;
        public bool DisplaySummaryPopup
        {
            get { return _displaySumarry;  }
            set
            {
                _displaySumarry = value;
                OnPropertyChanged();
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;

        protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            var handler = PropertyChanged;
            if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }

我认为您的 INotifyPropertyChanged 实现是导致问题的原因。我自己尝试了代码并且现在正在工作。

在尝试追踪这个问题后,我发现问题与上下文菜单有关。我知道这一点是因为根据上面的答案,我没有通过上下文菜单启动我的弹出窗口,而是从测试按钮启动它,并且一切都按预期工作。

我仍然不知道这个问题的确切原因,但我认为这与以下事实有关:上下文菜单本身是弹出窗口的子类,并且焦点没有正确设置在新弹出窗口上,因此它永远不会检测到弹出窗口丢失并关闭。

为了解决我的问题,我在弹出窗口中添加了一个关闭按钮,然后每当托管弹出窗口的控件中的活动选项卡发生更改时,它都会触发弹出窗口拾取并关闭的事件。

有同样的问题。原因是切换按钮的 ClickMode 属性 设置为 "Press"。将其设置回 "Release" 即可解决 :).

对我来说,解决方案是在弹出窗口代码隐藏的构造函数中添加这一行:

LostFocus += delegate { this.IsOpen = false; };

花了很多时间,当这样一个快速的线路就花了:)

我遇到过几次同样的问题。每次发生时,当弹出窗口从事件中将其“isOpen”属性 更改为 true 时,该事件是从 listview 或 datagrid 元素引发的,例如 selectedItemChanged 事件或 items mouseUp 事件。我不知道原因,但是通过使用以下代码从另一个任务打开弹出窗口解决了这个问题:

Task.Run(()=> Dispatcher.Invoke( () => myPopup.IsOpen = true));

Dispatcher 用于避免从主线程以外的其他线程更改任何 GUI 对象 属性 引起的异常。