9

So I have a Context Menu And a MenuItem in it which breaks out into a list of names:

<ContextMenu>
    <MenuItem Header="Set As Default For" ItemsSource="{Binding Source={StaticResource Names}}">
       <MenuItem.ItemContainerStyle>
           <Style TargetType="MenuItem">
                <Setter Property="Header" Value={Binding Name}/>
                <Setter Property="Command" Value="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=MenuItem}, Path=DataContext.DoSomething}" />
                <Setter Property="CommandParameter" Value="{Binding }" />
            </Style>
         </MenuItem.ItemContainerStyle>
     </MenuItem>
</ContextMenu>

Now the above code works file and displays my list of names. Now I would like to add an Icon next to each Name using a Pack URI.. So from this question I can see the best way to do it is to template the Header so I tried that first like the question

<ContextMenu>
    <MenuItem Header="Set As Default For" ItemsSource="{Binding Source={StaticResource Names}}">
       <MenuItem.ItemContainerStyle>
           <Style TargetType="MenuItem">
                <Setter Property="Header">
                    <Setter.Value>
                         <StackPanel>
                               <Image Width="20" Height="20" Source="/MyProj;component/Resources/MyImg.png" />
                              <ContentPresenter Content="{Binding Name}" />
                          </StackPanel>
                     </Setter.Value>
                 </Setter>
                 <Setter Property="Command" Value="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=MenuItem}, Path=DataContext.DoSomething}" />
                 <Setter Property="CommandParameter" Value="{Binding }" />
            </Style>
         </MenuItem.ItemContainerStyle>
     </MenuItem>
</ContextMenu>

but this gave me the error:

Specified element is already the logical child of another element. Disconnect it first.

So I after some research I tried:

<ContextMenu>
    <MenuItem Header="Set As Default For" ItemsSource="{Binding Source={StaticResource Names}}">
       <MenuItem.ItemContainerStyle>
           <Style TargetType="MenuItem">
                <Setter Property="Header">
                    <Setter.Value>
                         <ControlTemplate>
                             <StackPanel>
                                   <Image Width="20" Height="20" Source="/MyProj;component/Resources/MyImg.png" />
                                    <ContentPresenter Content="{Binding Name}" />
                              </StackPanel>
                           </ControlTemplate>
                     </Setter.Value>
                 </Setter>
                 <Setter Property="Command" Value="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=MenuItem}, Path=DataContext.DoSomething}" />
                 <Setter Property="CommandParameter" Value="{Binding }" />
            </Style>
         </MenuItem.ItemContainerStyle>
     </MenuItem>
</ContextMenu>

But now all my names are ControlTemplate and no icon is displayed...

How do I add an icon to a Context Menu's Menu Item through ItemContainerStyle?

EDIT

I've tried:

   <Setter Property="Header" Value="{Binding Name}"/>
   <Setter Property="Icon">
       <Setter.Value>
           <Image Width="20" Height="20" Source="/MyProj;component/Resources/MyImg.png" />
       </Setter.Value>
    </Setter>

And I get an icon rendering but only for the last item in my menu?

Community
  • 1
  • 1
JKennedy
  • 18,150
  • 17
  • 114
  • 198
  • Either use `HeaderTemplate` instead of `Header` and use `DataTemplate` instead of `ControlTemplate` but personally I would set `Icon` property as another `Setter` in your `Style`. Your code will place icon in the content part of `MenuItem`, not the `Icon` part – dkozl Mar 17 '15 at 11:28
  • @dkozl you are right using `HeaderTemplate` and `DataTemplate` worked. And you were also right in that my code placed the icon inside the Header which wasn't what I'd planned. Do you know how to set the icon using Pack URI in a style? – JKennedy Mar 17 '15 at 11:39
  • try setting [`x:Shared`](https://msdn.microsoft.com/en-us/library/aa970778(v=vs.110).aspx) to false against your `Style` like ` – dkozl Mar 17 '15 at 11:51
  • @dkozl I can't seem to find the `x:shared` attribute on my style? – JKennedy Mar 17 '15 at 11:54
  • Sorry, it can be applied only to items in `ResourceDictionary`. You need to move `Style` to `ContextMenu.Resources` with some `x:Key` and set `ItemContainerStyle` as `StaticResource`. Also make sure you set `x:Shared` not `x:shared` – dkozl Mar 17 '15 at 11:58
  • I get the error: `Shared attribute in namespace 'http://schemas.microsoft.com/winfx/2006/xaml' can be used only in compiled resource dictionaries.` at runtime – JKennedy Mar 17 '15 at 12:03

1 Answers1

13

The problem is that you cannot use one visual in more then one place. You can do it either by using HeaderTemplate instead of Header, but use DataTemplate instead of ControlTemplate

<Style TargetType="MenuItem">
   <Setter Property="HeaderTemplate">
      <Setter.Value>
         <DataTemplate>
            <StackPanel>
               <Image Width="20" Height="20" Source="/MyProj;component/Resources/MyImg.png" />
               <ContentPresenter Content="{Binding Name}" />
            </StackPanel>
         </DataTemplate>
      </Setter.Value>
   </Setter>
   <!-- other setters -->
</Style>

Note that this solution will put icon in the content part of MenuItem, not the icon. Another solution is to set Icon property of MenuItem as another Setter but in this case Image needs to be separate Resource with x:Shared set to false otherwise you'll end up with the same problem where only last item has an icon.

<ContextMenu>
   <ContextMenu.Resources>
      <Image Width="20" Height="20" Source="/MyProj;component/Resources/MyImg.png" x:Key="myMenuIcon" x:Shared="False" />
   </ContextMenu.Resources>
   <MenuItem Header="Set As Default For" ItemsSource="{Binding Source={StaticResource Names}}">
      <MenuItem.ItemContainerStyle>
         <Style TargetType="{x:Type MenuItem}">
            <Setter Property="Header" Value="{Binding Name}"/>
            <Setter Property="Icon" Value="{StaticResource myMenuIcon}"/>
         </Style>
      </MenuItem.ItemContainerStyle>
   </MenuItem>
</ContextMenu>
dkozl
  • 32,814
  • 8
  • 87
  • 89
  • I've copied the second example using the `x:Shared` attribute but I still get the error `Shared attribute in namespace 'http://schemas.microsoft.com/winfx/2006/xaml' can be used only in compiled resource dictionaries.` at runtime. Thanks for your help though – JKennedy Mar 17 '15 at 12:42
  • I've tested that. Against which element do you set `x:Shared`? It shoukld be set against _myMenuIcon_ only, which is in `ContextMenu.Resources` – dkozl Mar 17 '15 at 12:44
  • It's set against `myMenuIcon` my project is a `plugin` which is a `.dll` and loaded into my application at runtime... that may affect it? my error is being thrown back up to my main application – JKennedy Mar 17 '15 at 13:00
  • @user1 You have to put it into the ``. Then you can apply a Binding on the Source and voilla, dynamic icons in the right place :) – bytecode77 Dec 20 '16 at 12:00