Mgamerz
Mgamerz

Reputation: 2890

WPF shared menu between main top menu and right click context menu

I'm trying to make a shared menu between something on my top menu bar of my app, and the right click context menu of something in my interface in WPF. I've googled aroudn but I can't figure out hwo to share ONLY the menuitems list.

Here is a picture of the UI to help describe it:

enter image description here

The way this works is when an item in the list (as shown in the background) is selected, this menu becomes available to use. I would like to make it so that when you right click an item in the list, it also shows the same menu. I would like to avoid duplicating code, so I defined a resource for MenuItem in my window resources:

<MenuItem x:Key="modUtilsMenu">
    <MenuItem Header="{Binding SelectedMod.ModName}" IsEnabled="False" FontWeight="Bold" />
    <MenuItem Header="{DynamicResource string_Checkforupdates}" Command="{Binding SelectedModCheckForUpdatesCommand}" ToolTip="{DynamicResource string_tooltip_checksForUpdatesToThisMod}" >
        <MenuItem.Icon>
            <fa:ImageAwesome Style="{StaticResource EnableDisableImageStyle}" Icon="Cloud" Foreground="{DynamicResource {x:Static adonisUi:Brushes.ForegroundBrush}}" Height="16" Width="16"/>
        </MenuItem.Icon>
    </MenuItem>
    <MenuItem Header="{DynamicResource string_RestoremodfromME3Tweaks}" Command="{Binding RestoreModFromME3TweaksCommand}" ToolTip="{DynamicResource string_tooltip_forcesUpdateCheck}" >
        <MenuItem.Icon>
            <fa:ImageAwesome Style="{StaticResource EnableDisableImageStyle}" Icon="CloudDownload" Foreground="{DynamicResource {x:Static adonisUi:Brushes.ForegroundBrush}}" Height="16" Width="16" RenderOptions.BitmapScalingMode="HighQuality"/>
        </MenuItem.Icon>
    </MenuItem>
    ...

I then add it to the interface as a sub element of the Mod Utils menuitem:

<MenuItem Header="{DynamicResource string_ModUtils}" Padding="4" IsEnabled="{Binding SelectedMod,  Converter={StaticResource NullEnabledConverter}}">
     <StaticResource ResourceKey="modUtilsMenu"/>
</MenuItem>

Obviously this doesn't work as it has a second MenuItem defined in the resource.

enter image description here

However, I am not sure how I can store a "list" of menu items to add as children of another object, as the root container element of MenuItem and ContextMenu are not the same. These are all command based menu items. I will have the same issue with a context menu too - how do I only share the contents and not the container? Do I have to do data binding?

I have looked at How do I share a menu definition between a context menu and a regular menu in WPF, but that seems to be just for single menu items. I suppose I could do it for every one of them, but I'm looking to see if there's a way to do this where I only have to update it in one place instead of three to make it work.

Upvotes: 2

Views: 1254

Answers (1)

BionicCode
BionicCode

Reputation: 28988

Menu and ContextMenu are both of type ItemsControl. You can treat them like this e.g. bind to a collection of item models and specify a DataTemplate.

The following example creates a collection of MenuItem as XAML resource.
To allow multiple instances of the collection it is important to to set the x:Shared attribute to False. Otherwise the menu will be rendered only in one location of the visual tree, no matter the number of references:

<Window>
  <Window.Resources>
    <x:Array x:Key="SharedMenuItems" 
             Type="MenuItem" 
             x:Shared="False">
      <MenuItem Header="File">
        <MenuItem Header="Save" />
      </MenuItem>
      <MenuItem Header="Settings" />
    </x:Array>
  </Window.Resources>

  <StackPanel x:Name="RootPanel" viewModels:Item.IsMarkedAsRead="True">
    <Menu ItemsSource="{StaticResource SharedMenuItems}" />

    <Grid>
      <Grid.ContextMenu>
        <ContextMenu ItemsSource="{StaticResource SharedMenuItems}" />
      </Grid.ContextMenu>

    </Grid>
  </StackPanel>
</Window>

Upvotes: 3

Related Questions