WPF Объединение ContextMenu разных контролов

81
10 апреля 2021, 00:00

Есть два любых контрола. Один главный, второй дочерний. У каждого есть свой ContextMenu. Нужно, чтобы вызвав ContextMenu у дочернего там был MenuItem и главного. Объединение я сделал, но команды не работают. Как правильно объединить ContextMenu и чтобы работали команды? MainWindow:

 <Window.DataContext>
    <local:MainMenuViewModel></local:MainMenuViewModel>
</Window.DataContext>
<StackPanel Width="100" Height="150" Background="Red">
    <StackPanel.ContextMenu>
        <ContextMenu>
            <MenuItem Header="Main Context Menu" Command="{Binding TestCommand}"></MenuItem>
        </ContextMenu>
    </StackPanel.ContextMenu>
    <Button Width="100" Height="100" Content="Button" Background="Red">
        <local:InheritMenu.ParentMenu>
            <Binding Path="ContextMenu" RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType={x:Type StackPanel}}" />
        </local:InheritMenu.ParentMenu>
        <local:InheritMenu.ContextMenu>
            <ContextMenu>
                <MenuItem Header="Button Context" Command="{Binding TestCommand}"></MenuItem>
            </ContextMenu>
        </local:InheritMenu.ContextMenu>
    </Button>
</StackPanel>

ViewModel

class MainMenuViewModel
{
    private RelayCommand testCommand;
    public ICommand TestCommand
    {
        get
        {
            if (testCommand == null)
            {
                testCommand = new RelayCommand(
                                        x =>
                                        {
                                            MessageBox.Show("TestCommand");
                                        },
                                        y => true);
            }
            return testCommand;
        }
    }
}

InheritMenu

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);
    }
}

RelayCommand

public class RelayCommand : ICommand
{
    private readonly Action<object> _execute;
    private readonly Predicate<object> _canExecute;
    public RelayCommand(Action<object> execute) : this(execute, null)
    {
    }
    public RelayCommand(Action<object> execute, Predicate<object> canExecute)
    {
        if (execute == null)
        {
            throw new ArgumentNullException("execute");
        }
        _execute = execute;
        _canExecute = canExecute;
    }
    public bool CanExecute(object parameter)
    {
        return _canExecute == null ? true : _canExecute(parameter);
    }
    public event EventHandler CanExecuteChanged
    {
        add
        {
            CommandManager.RequerySuggested += value;
        }
        remove
        {
            CommandManager.RequerySuggested -= value;
        }
    }
    public void Execute(object parameter)
    {
        _execute(parameter);
    }
}
READ ALSO
Гарантирует ли .NET при Select().ToList(), что порядок элементов не изменится?

Гарантирует ли .NET при Select().ToList(), что порядок элементов не изменится?

Допустим, есть List<SomeObject>, где SomeObject- это какой-то объект с десятком полей

96
Парсинг fb2 файла [закрыт]

Парсинг fb2 файла [закрыт]

Хотите улучшить этот вопрос? Добавьте больше подробностей и уточните проблему, отредактировав это сообщение

113
Как правильно повернуть часть объекта, чтобы она следила за другим объектом?

Как правильно повернуть часть объекта, чтобы она следила за другим объектом?

Создал объект состоящий из множества частей, как правильно повернуть одну из частей объекта, чтобы она следила за другим объектом, используя...

102
DoodleJump broken platform

DoodleJump broken platform

Делаю аналог DoodleJump

86