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()
        };
    }
}

我确实尝试了以下方法但没有成功:

恐怕您的 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.Capturednot 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 无法正常工作。