Here is a solution using a few Attached Properties to manually combine multiple ContextMenus together.
Note: Since it is using XAMLReader to clone the MenuItems, this solution won't preserve bindings in the inherited MenuItems.
using System.IO;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Markup;
using System.Xml;
namespace ContextMenuSample
{
public static class InheritMenu
{
public static readonly DependencyProperty ContextMenuProperty = DependencyProperty.RegisterAttached(
"ContextMenu", typeof(ContextMenu), typeof(InheritMenu), new FrameworkPropertyMetadata(null, OnContextMenuChanged));
private static void OnContextMenuChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
SetContextMenu(d as FrameworkElement);
}
public static void SetContextMenu(FrameworkElement element, ContextMenu value)
{
element.SetValue(ContextMenuProperty, value);
}
public static ContextMenu GetContextMenu(FrameworkElement element)
{
return (ContextMenu)element.GetValue(ContextMenuProperty);
}
public static readonly DependencyProperty ParentMenuProperty = DependencyProperty.RegisterAttached(
"ParentMenu", typeof(ContextMenu), typeof(InheritMenu), new FrameworkPropertyMetadata(null, OnParentMenuChanged));
private static void OnParentMenuChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
SetContextMenu(d as FrameworkElement);
}
public static void SetParentMenu(FrameworkElement element, ContextMenu value)
{
element.SetValue(ParentMenuProperty, value);
}
public static ContextMenu GetParentMenu(FrameworkElement element)
{
return (ContextMenu)element.GetValue(ParentMenuProperty);
}
private static void SetContextMenu(FrameworkElement element)
{
var context = GetContextMenu(element);
var parent = GetParentMenu(element);
if (context == null || parent == null) return;
var menu = new ContextMenu();
foreach (var item in parent.Items)
menu.Items.Add(SimpleXamlClone(item));
menu.Items.Add(new Separator());
foreach (var item in context.Items)
menu.Items.Add(SimpleXamlClone(item));
element.ContextMenu = menu;
}
public static object SimpleXamlClone(object original)
{
var xaml = XamlWriter.Save(original);
var reader = new StringReader(xaml);
var xml = XmlReader.Create(reader);
return XamlReader.Load(xml);
}
}
}
<Window x:Class="ContextMenuSample.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:l="clr-namespace:ContextMenuSample"
Title="Window1" Height="250" Width="500">
<Window.Resources>
<l:MyCommand x:Key="MainCommand" Message="Main Command!" />
<l:MyCommand x:Key="ScopeACommand" Message="Scope A Command!" />
<l:MyCommand x:Key="ScopeBCommand" Message="Scope B Command!" />
<l:MyCommand x:Key="ScopeCCommand" Message="Scope C Command!" />
<l:MyCommand x:Key="ScopeDCommand" Message="Scope D Command!" />
<Style TargetType="Label">
<Setter Property="HorizontalAlignment" Value="Center" />
</Style>
<Style TargetType="TextBox">
<Setter Property="HorizontalAlignment" Value="Center" />
</Style>
</Window.Resources>
<!-- Main Scope -->
<Grid Margin="8" Background="LightGray">
<Grid.ContextMenu>
<ContextMenu>
<MenuItem Header="Main Scope" Command="{StaticResource MainCommand}" />
</ContextMenu>
</Grid.ContextMenu>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition />
</Grid.RowDefinitions>
<Label Grid.ColumnSpan="2" Grid.Row="0">Main Scope</Label>
<Label Grid.ColumnSpan="2" Grid.Row="1">Check ContextMenu Here!</Label>
<!-- Scope A -->
<StackPanel Grid.Column="0" Grid.Row="2" Margin="8" Background="LightBlue">
<l:InheritMenu.ParentMenu>
<Binding Path="ContextMenu" RelativeSource="{RelativeSource AncestorType={x:Type Grid}}" />
</l:InheritMenu.ParentMenu>
<l:InheritMenu.ContextMenu>
<ContextMenu>
<MenuItem Header="Scope A" Command="{StaticResource ScopeACommand}" />
</ContextMenu>
</l:InheritMenu.ContextMenu>
<Label>Scope A</Label>
<Label>Check ContextMenu Here!</Label>
<!-- Scope C -->
<StackPanel Margin="8" Background="LightGreen">
<l:InheritMenu.ParentMenu>
<Binding Path="ContextMenu" RelativeSource="{RelativeSource AncestorType={x:Type StackPanel}}" />
</l:InheritMenu.ParentMenu>
<l:InheritMenu.ContextMenu>
<ContextMenu>
<MenuItem Header="Scope C" Command="{StaticResource ScopeCCommand}" />
</ContextMenu>
</l:InheritMenu.ContextMenu>
<Label>Scope C</Label>
<Label>Check ContextMenu Here!</Label>
</StackPanel>
</StackPanel>
<!-- Scope B -->
<StackPanel Grid.Column="1" Grid.Row="2" Margin="8" Background="LightCoral">
<l:InheritMenu.ParentMenu>
<Binding Path="ContextMenu" RelativeSource="{RelativeSource AncestorType={x:Type Grid}}" />
</l:InheritMenu.ParentMenu>
<l:InheritMenu.ContextMenu>
<ContextMenu>
<MenuItem Header="Scope B" Command="{StaticResource ScopeBCommand}" />
</ContextMenu>
</l:InheritMenu.ContextMenu>
<Label>Scope B</Label>
<Label>Check ContextMenu Here!</Label>
<!-- Scope D -->
<StackPanel Margin="8" Background="LightSalmon">
<l:InheritMenu.ParentMenu>
<Binding Path="ContextMenu" RelativeSource="{RelativeSource AncestorType={x:Type StackPanel}}" />
</l:InheritMenu.ParentMenu>
<l:InheritMenu.ContextMenu>
<ContextMenu>
<MenuItem Header="Scope D" Command="{StaticResource ScopeDCommand}" />
</ContextMenu>
</l:InheritMenu.ContextMenu>
<Label>Scope D</Label>
<Label>Check ContextMenu Here!</Label>
</StackPanel>
</StackPanel>
</Grid>
</Window>
public class MyCommand : ICommand
{
public string Message { get; set; }
public void Execute(object parameter) { MessageBox.Show(Message); }
public bool CanExecute(object parameter) { return true; }
public event EventHandler CanExecuteChanged;
}