Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

WPF XAML defined MenuItem reuse starts working, then disappears

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,

enter image description here

So does the second:

enter image description here

But when you navigate back to the first menu, the MenuItems disappear:

enter image description here

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:

  1. Win 10, VS2013 Ult V12.0.40629.00 Update 5, .NET V4.6.0138
  2. Win 7, VS2013 Prem V12.0.31101.00 Update 4, .NET V4.5.51209
like image 418
Taterhead Avatar asked Mar 08 '16 21:03

Taterhead


1 Answers

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>
like image 197
Peter Duniho Avatar answered Nov 03 '22 16:11

Peter Duniho