WPF XAML 定义的 MenuItem 重用开始工作,然后消失

WPF XAML defined MenuItem reuse starts working, then disappears

以下简单代码尝试在两个单独的菜单上重用 Window.Resources 中定义的 MenuItem。

<Window x:Class="WpfApplication.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:collections="clr-namespace:System.Collections;assembly=mscorlib"
        Title="MainWindow" Height="350" Width="525">
  <Window.Resources>
    <collections:ArrayList x:Key="menuItemValues">
       <MenuItem Header="First"/>
       <MenuItem Header="Second"/>
       <MenuItem Header="Third"/>
    </collections:ArrayList>
    <MenuItem x:Key="menuItem" x:Shared="False"
              ItemsSource="{StaticResource menuItemValues}"
              Header="Shared menu item"/>
  </Window.Resources>
  <StackPanel>
    <Menu HorizontalAlignment="Left" VerticalAlignment="Top">
      <StaticResource ResourceKey="menuItem"/>
      <StaticResource ResourceKey="menuItem"/>
    </Menu>
  </StackPanel>
</Window>

这开始很好,当您第一次 select 菜单时,一切看起来都很好。第一个菜单有所需的 MenuItems,

第二个也是:

但是当您导航回第一个菜单时,MenuItems 消失了:

有人可以解释为什么菜单会消失,以及如何让它起作用吗?

这是在调查另一个 that was getting an exception. I tried to use a strategy discussed on another SO question 时发现的,它似乎解决了问题,直到您第二次导航回菜单并且它消失了。

我已经在两台不同的机器上重现了这个问题:

  1. Win 10、VS2013 Ult V12.0.40629.00 更新 5、.NET V4.6.0138
  2. Win 7、VS2013 Prem V12.0.31101.00 更新 4、.NET V4.5.51209

这是因为,虽然 top-level MenuItemx:Shared="False",但 collection 中的 MenuItem object 不是.它们在 ArrayList collection 中各声明一次,然后在创建的 menuItem object 的每个实例中重复使用。

要使代码正常工作,您需要强制 WPF 创建新实例。一种选择是将 x:Shared="False" 也应用于 collection。例如:

<Window x:Class="WpfApplication.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:collections="clr-namespace:System.Collections;assembly=mscorlib"
        Title="MainWindow" Height="350" Width="525">
  <Window.Resources>
    <collections:ArrayList x:Key="menuItemValues" x:Shared="False">
       <MenuItem Header="First"/>
       <MenuItem Header="Second"/>
       <MenuItem Header="Third"/>
    </collections:ArrayList>
    <MenuItem x:Key="menuItem" x:Shared="False"
              ItemsSource="{StaticResource menuItemValues}"
              Header="Shared menu item"/>
  </Window.Resources>
  <StackPanel>
    <Menu HorizontalAlignment="Left" VerticalAlignment="Top">
      <StaticResource ResourceKey="menuItem"/>
      <StaticResource ResourceKey="menuItem"/>
    </Menu>
  </StackPanel>
</Window>

当然,假设项目只是给定 Header 值,您可以只使用默认的 MenuItem 模板行为,通过提供 string 值而不是 MenuItem 值。这允许您重用 collection 本身(它没有潜在的重用能力):

<Window x:Class="WpfApplication.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:s="clr-namespace:System;assembly=mscorlib"
        xmlns:collections="clr-namespace:System.Collections;assembly=mscorlib"
        Title="MainWindow" Height="350" Width="525">
  <Window.Resources>
    <collections:ArrayList x:Key="menuItemValues">
      <s:String>First</s:String>
      <s:String>Second</s:String>
      <s:String>Third</s:String>
    </collections:ArrayList>
    <MenuItem x:Key="menuItem" x:Shared="False"
              ItemsSource="{StaticResource menuItemValues}"
              Header="Shared menu item"/>
  </Window.Resources>
  <StackPanel>
    <Menu HorizontalAlignment="Left" VerticalAlignment="Top">
      <StaticResource ResourceKey="menuItem"/>
      <StaticResource ResourceKey="menuItem"/>
    </Menu>
  </StackPanel>
</Window>