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 时发现的,它似乎解决了问题,直到您第二次导航回菜单并且它消失了。
我已经在两台不同的机器上重现了这个问题:
- Win 10、VS2013 Ult V12.0.40629.00 更新 5、.NET V4.6.0138
- Win 7、VS2013 Prem V12.0.31101.00 更新 4、.NET V4.5.51209
这是因为,虽然 top-level MenuItem
是 x: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>
以下简单代码尝试在两个单独的菜单上重用 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 消失了:
有人可以解释为什么菜单会消失,以及如何让它起作用吗?
这是在调查另一个
我已经在两台不同的机器上重现了这个问题:
- Win 10、VS2013 Ult V12.0.40629.00 更新 5、.NET V4.6.0138
- Win 7、VS2013 Prem V12.0.31101.00 更新 4、.NET V4.5.51209
这是因为,虽然 top-level MenuItem
是 x: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>