ToolBarOverflow 面板内的弹出窗口无法正常工作
Popup inside ToolBarOverflow Panel does not work properly
我的应用程序中有一个 ToolBar
导致问题。
我在 ToolBar
中有 "DropDown" 个按钮 (ToggleButton
+ Popup
) 如果这些下拉菜单位于 ToolBar
的可见部分,则它们不会正常工作如果它们位于 ToolBarOverflowPanel
.
中,则可以正常工作
如果我在 ToolBarOverflowPanel
中打开下拉菜单,Popup
似乎没有获得焦点。仍然有悬停效果(与可见工具栏中相同 Popup
的行为相反,它似乎消耗了所有 Mouse
事件)我仍然可以单击任何其他打开下一个 Popup
而第一个保持打开状态。
以下代码是重现该行为的完整工作示例。
<Window x:Class="ToolbarProblem.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Height="350"
Width="525">
<StackPanel>
<ToolBar ItemsSource="{Binding Items}">
<ToolBar.ItemTemplate>
<DataTemplate >
<StackPanel VerticalAlignment="Center"
Orientation="Horizontal">
<ToggleButton Name="ToggleButton"
ToolTip="ToolTip"
IsChecked="{Binding ElementName=ContextActionPopup, Path=IsOpen, Mode=TwoWay}"
ClickMode="Release">
<TextBlock Text="ICON"/>
</ToggleButton>
<Popup Name="ContextActionPopup"
StaysOpen="False">
<Border x:Name="Border"
Background="White"
Padding="1"
Visibility="Visible">
<TextBlock Text="Content" />
</Border>
</Popup>
</StackPanel>
</DataTemplate>
</ToolBar.ItemTemplate>
</ToolBar>
</StackPanel>
namespace ToolbarProblem
{
using System.Collections.Generic;
public partial class MainWindow
{
public MainWindow()
{
this.InitializeComponent();
this.DataContext = new MainWindowViewModel();
}
}
public class MainWindowViewModel
{
public List<object> Items { get; } = new List<object>
{
new object(),
new object(),
new object(),
new object(),
new object(),
new object(),
new object(),
new object(),
new object(),
new object(),
new object(),
new object(),
new object(),
new object(),
new object(),
new object(),
new object(),
new object(),
new object(),
new object()
};
}
}
我确实尝试了以下方法但没有成功:
- 添加一些代码来调用
Popup.Focus
- 将
ToggleButton.ClickMode
改为所有可能的
- 将
Popup.StaysOpen
属性 设置为 true 似乎有效,但是
当然不适合我的目标
恐怕您的 XAML 永远无法正常工作。您可以在 Popup
控制代码中找到原因。如果你设置StaysOpen
属性为false,Popup
打开时,会调用这个私有方法(用ILSpy检查即可):
private void EstablishPopupCapture()
{
if (!this._cacheValid[1] && this._popupRoot.Value != null && !this.StaysOpen && Mouse.Captured == null)
{
Mouse.Capture(this._popupRoot.Value, CaptureMode.SubTree);
this._cacheValid[1] = true;
}
}
因此,如果没有其他控件捕获鼠标事件(即 Mouse.Captured == null
),您的弹出窗口将捕获它们
to determine when one of these events occurs outside the Popup control.
正如 MSDN 所说。请注意,Capture
方法和 Captured
属性是静态的,因此使用 Mouse
class.
一次只能捕获一个控件
现在看看 Toolbar
默认样式:您会发现它的 Popup
控件,名为 "OverflowPopup",有它的 StaysOpen
属性 设置为 false。
因此,当您单击溢出缩略图时,"OverflowPopup" 在打开时会调用 EstablishPopupCapture
。在本例中 Mouse.Captured
为空,因此它可以捕获鼠标事件。
一段时间后,您单击 "OverflowPopup" 内的 ToggleButton
(因此它将继续保持打开状态)。现在您的 Popup - 打开时 - 调用 EstablishPopupCapture
,但这次 Mouse.Captured
是 not null。所以使用Mouse
class.
是无法监听鼠标事件的
我想您应该考虑更改 XAML 或采用不同的解决方案(例如,您可以为工具栏编写自己的模板,以便将 OverflowPopup 的 StaysOpen
属性 设置为正确)。
这是一个简化的解释,但事实是,不可能有两个或更多打开的弹出窗口将 StaysOpen 设置为 false:它们根本无法按预期工作。试试 运行 这个 XAML:
<StackPanel Orientation="Horizontal">
<Button Content="I am button 1" Name="btn1" Height="20" />
<Button Content="I am button 2" Name="btn2" Height="20" />
<Popup StaysOpen="False" IsOpen="True" PlacementTarget="{Binding ElementName=btn1}">
<TextBlock Text="Popup1" Margin="6" Background="Red" />
</Popup>
<Popup StaysOpen="False" IsOpen="True" PlacementTarget="{Binding ElementName=btn2}">
<TextBlock Text="Popup2" Margin="6" Background="Red" />
</Popup>
</StackPanel>
您会发现 Popup2 无法正常工作。
我的应用程序中有一个 ToolBar
导致问题。
我在 ToolBar
中有 "DropDown" 个按钮 (ToggleButton
+ Popup
) 如果这些下拉菜单位于 ToolBar
的可见部分,则它们不会正常工作如果它们位于 ToolBarOverflowPanel
.
如果我在 ToolBarOverflowPanel
中打开下拉菜单,Popup
似乎没有获得焦点。仍然有悬停效果(与可见工具栏中相同 Popup
的行为相反,它似乎消耗了所有 Mouse
事件)我仍然可以单击任何其他打开下一个 Popup
而第一个保持打开状态。
以下代码是重现该行为的完整工作示例。
<Window x:Class="ToolbarProblem.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Height="350"
Width="525">
<StackPanel>
<ToolBar ItemsSource="{Binding Items}">
<ToolBar.ItemTemplate>
<DataTemplate >
<StackPanel VerticalAlignment="Center"
Orientation="Horizontal">
<ToggleButton Name="ToggleButton"
ToolTip="ToolTip"
IsChecked="{Binding ElementName=ContextActionPopup, Path=IsOpen, Mode=TwoWay}"
ClickMode="Release">
<TextBlock Text="ICON"/>
</ToggleButton>
<Popup Name="ContextActionPopup"
StaysOpen="False">
<Border x:Name="Border"
Background="White"
Padding="1"
Visibility="Visible">
<TextBlock Text="Content" />
</Border>
</Popup>
</StackPanel>
</DataTemplate>
</ToolBar.ItemTemplate>
</ToolBar>
</StackPanel>
namespace ToolbarProblem
{
using System.Collections.Generic;
public partial class MainWindow
{
public MainWindow()
{
this.InitializeComponent();
this.DataContext = new MainWindowViewModel();
}
}
public class MainWindowViewModel
{
public List<object> Items { get; } = new List<object>
{
new object(),
new object(),
new object(),
new object(),
new object(),
new object(),
new object(),
new object(),
new object(),
new object(),
new object(),
new object(),
new object(),
new object(),
new object(),
new object(),
new object(),
new object(),
new object(),
new object()
};
}
}
我确实尝试了以下方法但没有成功:
- 添加一些代码来调用
Popup.Focus
- 将
ToggleButton.ClickMode
改为所有可能的 - 将
Popup.StaysOpen
属性 设置为 true 似乎有效,但是 当然不适合我的目标
恐怕您的 XAML 永远无法正常工作。您可以在 Popup
控制代码中找到原因。如果你设置StaysOpen
属性为false,Popup
打开时,会调用这个私有方法(用ILSpy检查即可):
private void EstablishPopupCapture()
{
if (!this._cacheValid[1] && this._popupRoot.Value != null && !this.StaysOpen && Mouse.Captured == null)
{
Mouse.Capture(this._popupRoot.Value, CaptureMode.SubTree);
this._cacheValid[1] = true;
}
}
因此,如果没有其他控件捕获鼠标事件(即 Mouse.Captured == null
),您的弹出窗口将捕获它们
to determine when one of these events occurs outside the Popup control.
正如 MSDN 所说。请注意,Capture
方法和 Captured
属性是静态的,因此使用 Mouse
class.
现在看看 Toolbar
默认样式:您会发现它的 Popup
控件,名为 "OverflowPopup",有它的 StaysOpen
属性 设置为 false。
因此,当您单击溢出缩略图时,"OverflowPopup" 在打开时会调用 EstablishPopupCapture
。在本例中 Mouse.Captured
为空,因此它可以捕获鼠标事件。
一段时间后,您单击 "OverflowPopup" 内的 ToggleButton
(因此它将继续保持打开状态)。现在您的 Popup - 打开时 - 调用 EstablishPopupCapture
,但这次 Mouse.Captured
是 not null。所以使用Mouse
class.
我想您应该考虑更改 XAML 或采用不同的解决方案(例如,您可以为工具栏编写自己的模板,以便将 OverflowPopup 的 StaysOpen
属性 设置为正确)。
这是一个简化的解释,但事实是,不可能有两个或更多打开的弹出窗口将 StaysOpen 设置为 false:它们根本无法按预期工作。试试 运行 这个 XAML:
<StackPanel Orientation="Horizontal">
<Button Content="I am button 1" Name="btn1" Height="20" />
<Button Content="I am button 2" Name="btn2" Height="20" />
<Popup StaysOpen="False" IsOpen="True" PlacementTarget="{Binding ElementName=btn1}">
<TextBlock Text="Popup1" Margin="6" Background="Red" />
</Popup>
<Popup StaysOpen="False" IsOpen="True" PlacementTarget="{Binding ElementName=btn2}">
<TextBlock Text="Popup2" Margin="6" Background="Red" />
</Popup>
</StackPanel>
您会发现 Popup2 无法正常工作。