【问题标题】:AvalonDock + UserControl + DataGrid + ContextMenu command routing issueAvalonDock + UserControl + DataGrid + ContextMenu 命令路由问题
【发布时间】:2010-05-14 16:18:40
【问题描述】:

MenuItemsContextMenu 进行命令传播时,我遇到了奇怪的行为。

我有以下类型的布局:ContextMenuDataGrid 内的每个 DataGridRow 设置在 UserControl 内,而后者又在 AvalonDock 的 DockableContent 内。如果我在我的网格周围摆脱 either 停靠或 UserControl,则没有问题。 ListBox 而不是 DataGrid 也没有这个问题。

<Window x:Class="DockAndMenuTest.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:ad="clr-namespace:AvalonDock;assembly=AvalonDock"
        Title="MainWindow" Height="350" Width="525">
    <ad:DockingManager>
        <ad:DocumentPane>
            <ad:DockableContent Title="Doh!">
                <UserControl>
                    <UserControl.CommandBindings>
                        <CommandBinding Command="Zoom" 
                                        Executed="ExecuteZoom" 
                                        CanExecute="CanZoom"/>
                    </UserControl.CommandBindings>
                    <DataGrid Name="_evilGrid">
                        <DataGrid.Resources>
                            <Style TargetType="DataGridRow">
                                <Setter Property="ContextMenu">
                                    <Setter.Value>
                                        <ContextMenu>
                                            <MenuItem Command="Zoom"/>
                                        </ContextMenu>
                                    </Setter.Value>
                                </Setter>
                            </Style>
                        </DataGrid.Resources>
                    </DataGrid>
                </UserControl>
            </ad:DockableContent>
        </ad:DocumentPane>
    </ad:DockingManager>
</Window>

代码隐藏也很简单:

public partial class MainWindow
{
    public MainWindow()
    {
        InitializeComponent();

        _evilGrid.ItemsSource =
            new[]
                {
                    Tuple.Create(1, 2, 3),
                    Tuple.Create(4, 4, 3),
                    Tuple.Create(6, 7, 1),
                };
    }

    private void ExecuteZoom(object sender, ExecutedRoutedEventArgs e)
    {
        MessageBox.Show("zoom !");
    }

    private void CanZoom(object sender, CanExecuteRoutedEventArgs e)
    {
        e.CanExecute = true;
    }
}

所以问题出在这里:右键单击所选行(如果它在右键单击之前被选中)我的命令被禁用。在这种情况下,命令是“缩放”,但可以是任何其他命令,包括自定义命令。

我不知道这里出了什么问题。 SNOOP 表明,在这种传播失败的情况下,CanExecute 不是由 CanExecute 处理,而是由停靠标头的一部分“PART_ShowContextMenuButton”(Button) 处理。

我在 AvalonDock 中托管的 UserControls 内的 UI 命令传播存在其他问题,但这个最容易重现。

【问题讨论】:

    标签: wpf user-controls datagrid routed-commands avalondock


    【解决方案1】:

    ContextMenu 是一个弹出窗口,因此它的 FocusScope 附加属性设置为 true:

    来自MSDN

    焦点范围是一个容器元素 跟踪 FocusManager..::.FocusedElement 内 其范围。默认情况下,窗口 类是一个焦点范围, 菜单、上下文菜单和工具栏 类。作为焦点的元素 scope 已将 IsFocusScope 设置为 false。

    基本上它还告诉命令停止在可视化树中进一步查看。

    所以你有两个选择

    1. 在上下文菜单对象上设置FocusManager.IsFocusScope="True"

    2. 或者移动您的 Command 绑定,以便您绑定到 ContextMenu 而不是 UserControl,如下所示:

    代码示例:

    <ContextMenu FocusManager.IsFocusScope="False">
        <ContextMenu.CommandBindings>
            <CommandBinding Command="Zoom" 
                    Executed="ExecuteZoom" 
                    CanExecute="CanZoom"/>
        </ContextMenu.CommandBindings>
             <MenuItem Command="Zoom"/>
    </ContextMenu>
    

    希望这会有所帮助! :)

    一些来自互联网领域的 FocusScope 噩梦故事:

    【讨论】:

    • 这样做并没有解决问题,但经过几个小时的挖掘后,我找到了适合我的案例的解决方案:我在 UserControl 级别(...),现在命令事件正在正确路由。非常感谢您为我指明了正确的方向!
    • 对不起.. 我会把答案改成 True ;)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-27
    • 1970-01-01
    • 2011-10-24
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多