键盘导航在带有模板的WPF菜单中不再有效

时间:2014-08-20 09:10:18

标签: wpf xaml menu menuitem

在绑定到集合的数据的WPF菜单中,我可以正确地设置所有内容,但使用键盘导航不再按预期工作。

考虑下面的XAML(您可以将其粘贴到像KaXaml这样的工具中)。

两件事:

  • 打开菜单并使用箭头键向右导航将默认选择打开的菜单项中的第一项。例如:

    • 点击' One'
    • 按向右箭头 - >菜单2打开但未选择任何内容
    • 再次按向右箭头 - >菜单三打开,第一项被选中
  • 浏览子项目并不起作用。按右箭头时,将打开下一个顶级菜单项,而不是向下钻取到子项

    • 点击' Two'
    • 按向左箭头
    • 按向右箭头 - >我们深入研究,选择One> A>我
    • 按向右箭头 - >没有什么可深入的,所以我们继续使用MenuItem Two
    • 按向右箭头 - >而不是深入研究两个> '约束财产' > '另一个绑定的属性',我们转到顶级MenuItem' Three'

如何确保'默认'使用键导航时的菜单行为?

这是您可以使用以下方法测试的XAML:

<Page
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
  <Grid>  
    <Menu VerticalAlignment="Top">
      <MenuItem Header="One">
        <MenuItem Header="A">
          <MenuItem Header="I" />
          <MenuItem Header="II" />
          <MenuItem Header="III" />
        </MenuItem>
        <MenuItem Header="B"/>
        <MenuItem Header="C"/>
      </MenuItem>

      <MenuItem Header="Two">
        <MenuItem.ItemContainerStyle>
            <Style TargetType="MenuItem">
              <Setter Property="Template">
                <Setter.Value>
                  <ControlTemplate>
                    <MenuItem>
                      <MenuItem.HeaderTemplate>
                        <DataTemplate>
                          <TextBlock>
                              <Run Text="Bound property" />
                          </TextBlock>
                        </DataTemplate>
                      </MenuItem.HeaderTemplate>
                      <MenuItem Header="Something"/>
                      <MenuItem Header="Something else"/>
                    </MenuItem>
                  </ControlTemplate>
                </Setter.Value>
              </Setter>
            </Style>
          </MenuItem.ItemContainerStyle>
        <MenuItem Header="A"/>
        <MenuItem Header="B"/>
        <MenuItem Header="C"/>
      </MenuItem>

      <MenuItem Header="Three">
        <MenuItem Header="A">
          <MenuItem Header="I" />
          <MenuItem Header="II" />
          <MenuItem Header="III" />
        </MenuItem>
        <MenuItem Header="B"/>
        <MenuItem Header="C"/>
      </MenuItem>

    </Menu>
  </Grid>
</Page>

更新

特别之处在于我的ControlTemplate中的子MenuItems应该为每个DataBound MenuItem添加。这是因为我有一个ObservableCollection,我将使用它在MenuItem&#34; Two&#34;中构建MenuItems。对于这些MenuItem中的每一个,我需要相同的子MenuItems。除了CommandParameter之外,它们将绑定到每个MenuItem的相同Command。

所以我最终想要的是:

Two
    Bound property 1
        Something
        Something else
    Bound property 2
        Something
        Something else
    Bound property 3
        Something
        Something else

2 个答案:

答案 0 :(得分:2)

您不应在MenuItem的模板中创建MenuItem元素。您应该为项目设置样式,使其具有绑定的内容。

我已经添加了XML作为菜单项的源,因此“Two”项目的内容绑定到XML(您可以将其替换为您的集合)。对于此解决方案,您应该有一个子菜单项的集合(一个用于所有顶级项目,而不是每个顶级项目)。键盘导航在以下示例中正常工作。

<Page
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <Page.Resources>
        <XmlDataProvider x:Key="MenuProvider" XPath="Items">
            <x:XData>
                <Items xmlns="">
                    <Item Title="Bound property 1" Parameter="1" />
                    <Item Title="Bound property 2" Parameter="2" />
                    <Item Title="Bound property 3" Parameter="3" />
                </Items>
            </x:XData>
        </XmlDataProvider>
        <XmlDataProvider x:Key="SubMenuProvider" XPath="Items">
            <x:XData>
                <Items xmlns="">
                    <Item Title="Something" />
                    <Item Title="Something else" />
                </Items>
            </x:XData>
        </XmlDataProvider>
    </Page.Resources>
    <Grid>
        <Menu VerticalAlignment="Top">
            <MenuItem Header="One">
                <MenuItem Header="A">
                    <MenuItem Header="I" />
                    <MenuItem Header="II" />
                    <MenuItem Header="III" />
                </MenuItem>
                <MenuItem Header="B" />
                <MenuItem Header="C" />
            </MenuItem>

            <MenuItem Header="Two" ItemsSource="{Binding Source={StaticResource MenuProvider}, XPath=*}">
                <MenuItem.ItemContainerStyle>
                    <Style TargetType="MenuItem">
                        <Setter Property="Header" Value="{Binding XPath=@Title}" />
                        <Setter Property="ItemsSource" Value="{Binding Source={StaticResource SubMenuProvider}, XPath=*}" />
                        <Setter Property="Tag" Value="{Binding XPath=@Parameter}" />
                        <Setter Property="ItemContainerStyle">
                            <Setter.Value>
                                <Style TargetType="MenuItem">
                                    <Setter Property="Header" Value="{Binding XPath=@Title}" />
                                    <Setter Property="CommandParameter" Value="{Binding Path=Tag, RelativeSource={RelativeSource AncestorType=MenuItem}}" />
                                </Style>
                            </Setter.Value>
                        </Setter>
                    </Style>
                </MenuItem.ItemContainerStyle>
            </MenuItem>

            <MenuItem Header="Three">
                <MenuItem Header="A">
                    <MenuItem Header="I" />
                    <MenuItem Header="II" />
                    <MenuItem Header="III" />
                </MenuItem>
                <MenuItem Header="B" />
                <MenuItem Header="C" />
            </MenuItem>
        </Menu>
    </Grid>
</Page>

答案 1 :(得分:1)

我确实重新设定了菜单项Two,同时保留了您的预期需求

    <MenuItem Header="Two">
        <MenuItem.ItemContainerStyle>
            <Style TargetType="MenuItem">
                <Setter Property="Header"
                        Value="Bound property" />
                <Setter Property="ItemsSource">
                    <Setter.Value>
                        <!--binding sub menu items to a collection-->
                        <x:ArrayExtension Type="sys:String"
                                          xmlns:sys="clr-namespace:System;assembly=mscorlib">
                            <sys:String>Something</sys:String>
                            <sys:String>Something else</sys:String>
                        </x:ArrayExtension>
                    </Setter.Value>
                </Setter>
            </Style>
        </MenuItem.ItemContainerStyle>
        <MenuItem />
        <MenuItem />
        <MenuItem />
    </MenuItem>

上面的示例解决了导航问题,同时根据需要保持对子项的绑定。 试一试,看看它有多接近。