The following simple code attempts to reuse a MenuItem defined in the Window.Resources on two separate Menus.
<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>
This starts out great and when you first select the menus, all looks well. The first menu has the desired MenuItems,
So does the second:
But when you navigate back to the first menu, the MenuItems disappear:
Can someone explain why the menu disappears and a way to get this to work?
This was discovered while investigating another SO question that was getting an exception. I tried to use a strategy discussed on another SO question and it seemed to solve the problem until you navigate back to the menu a second time and it disappears.
I have reproduced this issue on 2 separate machines:
This is happening because, while the top-level MenuItem
is x:Shared="False"
, the MenuItem
objects in your collection are not. They are declared once each in the ArrayList
collection, and then reused in each instance of the menuItem
object that's created.
To get the code to work, you'll need to force WPF to create new instances. One option would be to apply the x:Shared="False"
to the collection as well. For example:
<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>
Of course, given that the items are simply given Header
values, you could just use the default MenuItem
templating behavior, by providing string
values instead of MenuItem
values. This allows you to reuse the collection itself (which has no underlying inability for reuse):
<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>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With