即使使用 StaysOpen="false",WPF 弹出窗口也不会关闭
WPF popup wont close even with StaysOpen="false"
我正在努力实现以下目标:
- 用户在数据网格中调出上下文菜单。
- 用户选择一个上下文菜单项,然后打开一个弹出窗口并显示一些信息。
- 当用户单击应用程序中的其他任何地方而不是弹出窗口时,弹出窗口将关闭。
在我关闭弹出窗口之前一切正常。
从别处搜索我知道我需要将 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 对象 属性 引起的异常。
我正在努力实现以下目标:
- 用户在数据网格中调出上下文菜单。
- 用户选择一个上下文菜单项,然后打开一个弹出窗口并显示一些信息。
- 当用户单击应用程序中的其他任何地方而不是弹出窗口时,弹出窗口将关闭。
在我关闭弹出窗口之前一切正常。
从别处搜索我知道我需要将 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 对象 属性 引起的异常。