How to attach Command to wpf RibbonMenuButton?

2019-04-02 14:12发布

问题:

I want to know how to attach command to RibbonMenuButton item. The following is my initial attempt but the command is never called.

<ribbon:RibbonWindow x:Class="RibbonMenuDemo.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:ribbon="clr-namespace:Microsoft.Windows.Controls.Ribbon;assembly=RibbonControlsLibrary"
        Title="MainWindow"
        x:Name="RibbonWindow"
        Width="640" Height="480">

    <Grid x:Name="LayoutRoot">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>

        <ribbon:Ribbon x:Name="Ribbon">

            <ribbon:RibbonTab x:Name="HomeTab" 
                              Header="Home">
                <ribbon:RibbonGroup x:Name="Group1" 
                                    Header="Map">
                    <ribbon:RibbonMenuButton   ItemsSource="{Binding Regions}" 
                                         LargeImageSource="Images\LargeIcon.png" 
                                         Label="Regions"   >
                        <ribbon:RibbonMenuButton.ItemContainerStyle >
                            <Style TargetType="MenuItem" >
                                <Setter Property="Command" Value="{Binding RegionChangeCommand}" />
                                <Setter Property="CommandParameter" Value="{Binding Label}"></Setter>
                            </Style>
                        </ribbon:RibbonMenuButton.ItemContainerStyle>
                    </ribbon:RibbonMenuButton>
                </ribbon:RibbonGroup>

            </ribbon:RibbonTab>
        </ribbon:Ribbon> 
    </Grid>
</ribbon:RibbonWindow>

here is my code

using System.Windows.Navigation;
using System.Windows.Shapes;
using Microsoft.Windows.Controls.Ribbon;
using System.ComponentModel;
using System.Diagnostics;

namespace RibbonMenuDemo
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : RibbonWindow
    {
        RelayCommand regionChangeCommand;


        public MainWindow()
        {
            InitializeComponent();
            this.DataContext = new Map();
        }

        public RelayCommand RegionChangeCommand
        {
            get 
            {
                if (regionChangeCommand == null)
                    regionChangeCommand = new RelayCommand(param => OnRegionChange(param), param =>  false);

                return regionChangeCommand; 
            }
        } 
        private void OnRegionChange(object param)
        {
            var val = (string)param;
            MessageBox.Show(val);
        }
    }

    public class Map
    {
        public Map()
        {
            Regions = new List<string> 
            { 
                "EAST", "North", "West", "South" 
            };
        }
        public List<string> Regions
        {
            get;
            set;
        }
    }

    public class RelayCommand : ICommand
    {
        readonly Action<object> execute;
        readonly Predicate<object> canExecute;

        /// <summary>
        /// create new simple command
        /// </summary>
        /// <param name="execute">execute handler</param>
        /// <param name="canExecute">predicate to determin if can excute</param>
        public RelayCommand(Action<object> execute, Predicate<object> canExecute = null)
        {
            if (execute == null)
                throw new ArgumentNullException("execute handler required");

            this.execute = execute;
            Predicate<object> v = (x) => { return true; };
            this.canExecute = canExecute ?? v;
        }

        public void Execute(object parameter)
        {
            this.execute(parameter);
        }
        [DebuggerStepThrough]
        public bool CanExecute(object parameter)
        {
            return canExecute(parameter);
        }
        public event EventHandler CanExecuteChanged
        {
            add { CommandManager.RequerySuggested += value; }
            remove { CommandManager.RequerySuggested -= value; }
        }
    }
}

回答1:

Solved like this:

<ribbon:RibbonMenuButton DataContext="{Binding .}" ItemsSource="{Binding Regions}" 
    LargeImageSource="Images\LargeIcon.png" Label="Regions">
    <ribbon:RibbonMenuButton.ItemContainerStyle>
        <Style TargetType="MenuItem">
            <Setter Property="Command" Value="{Binding DataContext.RegionChangeCommand,
                RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type 
                ribbon:RibbonMenuButton}}}" />
            <Setter Property="CommandParameter" Value="{Binding Label}"></Setter>
        </Style>
    </ribbon:RibbonMenuButton.ItemContainerStyle>
</ribbon:RibbonMenuButton>

Adapted from the Click event routing on RibbonButton under RibbonMenuButton? page on the Visual Studio Forum on MSDN.