Command Binding in WPF Split Button

7 May 202110 minutes to read

The command and command parameter properties allow to execute any action on clicking either the button or the dropdown menu items.

  • Command - The Command property accept all commands derived from interface ICommand.
  • CommandParameter - The CommandParameter property allows the user to provide additional data required in the command handler in-order to perform any operation.
<Window x:Class="Split_Button_Command_Binding.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:Button_Sample"
        xmlns:Syncfusion="http://schemas.microsoft.com/netfx/2009/xaml/presentation"
        xmlns:syncfusion="http://schemas.syncfusion.com/wpf"
        mc:Ignorable="d"
        xmlns:syncfusionskin="clr-namespace:Syncfusion.SfSkinManager;assembly=Syncfusion.SfSkinManager.WPF"
        Title="MainWindow" Height="450" Width="800">
    <Window.DataContext>
        <local:SplitViewModel/>
    </Window.DataContext>
    <Grid VerticalAlignment="Center" HorizontalAlignment="Left">
        <Grid.RowDefinitions>
            <RowDefinition Height="30"/>
            <RowDefinition Height="30"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>
        <CheckBox IsChecked="{Binding CanPerformAction}" Grid.Row="0" Content="Can perform action in split button"/>
        <CheckBox IsChecked="{Binding CanPerformActionItem}" Grid.Row="1" Content="Can perform action in drop down items"/>
        <syncfusion:SplitButtonAdv Label="Country" SizeMode="Large" LargeIcon="Images\flaglarge.png" Command="{Binding ClickCommand}" CommandParameter="Action completed" Grid.Row="2" Height="72" Width="122">
            <syncfusion:DropDownMenuGroup>
                <syncfusion:DropDownMenuItem  HorizontalAlignment="Left" Header="India" Command="{Binding DropDownCommand}" CommandParameter="India">
                    <syncfusion:DropDownMenuItem.Icon>
                        <Image Source="Images/india.png"/>
                    </syncfusion:DropDownMenuItem.Icon>
                </syncfusion:DropDownMenuItem>
                <syncfusion:DropDownMenuItem  HorizontalAlignment="Left" Header="France" Command="{Binding DropDownCommand}" CommandParameter="France" >
                    <syncfusion:DropDownMenuItem.Icon>
                        <Image Source="Images/france.png"/>
                    </syncfusion:DropDownMenuItem.Icon>
                </syncfusion:DropDownMenuItem>
                <syncfusion:DropDownMenuItem  HorizontalAlignment="Left" Header="Germany" Command="{Binding DropDownCommand}" CommandParameter="Germany" >
                    <syncfusion:DropDownMenuItem.Icon>
                        <Image Source="Images/germany.png"/>
                    </syncfusion:DropDownMenuItem.Icon>
                </syncfusion:DropDownMenuItem>
                <syncfusion:DropDownMenuItem  HorizontalAlignment="Left" Header="Canada" Command="{Binding DropDownCommand}" CommandParameter="Canada" >
                    <syncfusion:DropDownMenuItem.Icon>
                        <Image Source="Images/Canada.png"/>
                    </syncfusion:DropDownMenuItem.Icon>
                </syncfusion:DropDownMenuItem>
                <syncfusion:DropDownMenuItem  HorizontalAlignment="Left" Header="China" Command="{Binding DropDownCommand}" CommandParameter="China" >
                    <syncfusion:DropDownMenuItem.Icon>
                        <Image Source="Images/china.png"/>
                    </syncfusion:DropDownMenuItem.Icon>
                </syncfusion:DropDownMenuItem>
            </syncfusion:DropDownMenuGroup >
        </syncfusion:SplitButtonAdv>
    </Grid>
</window>
public class DelegateCommand<T> : ICommand
{
    private Predicate<T> _canExecute;
    private Action<T> _method;
    bool _canExecuteCache = true;

    /// <summary>
    /// Initializes a new instance of the <see cref="DelegateCommand"/> class.
    /// </summary>
    /// <param name="method">The method.</param>
    public DelegateCommand(Action<T> method)
        : this(method, null)
    {
    }

    /// <summary>
    /// Initializes a new instance of the <see cref="DelegateCommand"/> class.
    /// </summary>
    /// <param name="method">The method.</param>
    /// <param name="canExecute">The can execute.</param>
    public DelegateCommand(Action<T> method, Predicate<T> canExecute)
    {
        _method = method;
        _canExecute = canExecute;
    }

    /// <summary>
    /// Defines the method that determines whether the command can execute in its current state.
    /// </summary>
    /// <param name="parameter">Data used by the command.  If the command does not require data to be passed, this object can be set to null.</param>
    /// <returns>
    /// true if this command can be executed; otherwise, false.
    /// </returns>
    public bool CanExecute(object parameter)
    {
        if (_canExecute != null)
        {
            bool tempCanExecute = _canExecute((T)parameter);

            if (_canExecuteCache != tempCanExecute)
            {
                _canExecuteCache = tempCanExecute;
                this.RaiseCanExecuteChanged();
            }
        }

        return _canExecuteCache;
    }

    /// <summary>
    /// Raises CanExecuteChanged event to notify changes in command status.
    /// </summary>
    public void RaiseCanExecuteChanged()
    {
        if (CanExecuteChanged != null)
        {
            CanExecuteChanged(this, new EventArgs());
        }
    }

    /// <summary>
    /// Defines the method to be called when the command is invoked.
    /// </summary>
    /// <param name="parameter">Data used by the command.  If the command does not require data to be passed, this object can be set to null.</param>
    public void Execute(object parameter)
    {
        if (_method != null)
            _method.Invoke((T)parameter);
    }

    #region ICommand Members

    /// <summary>
    /// 
    /// </summary>
    public event EventHandler CanExecuteChanged;

    #endregion
}

class DropDownViewModel: NotificationObject
{
    private bool _canperformaction = true;

    public DropDownViewModel()
    {
        ClickCommand = new DelegateCommand<object>(ClickAction, CanPerformClickAction);
    }
    public bool CanPerformAction
    {
        get
        {
            return _canperformaction;
        }
        set
        {
            _canperformaction = value;
            this.ClickCommand.RaiseCanExecuteChanged();
            this.RaisePropertyChanged("CanPerformAction");
        }
    }

    private bool CanPerformClickAction(object parameter)
    {
        return CanPerformAction;
    }

    public DelegateCommand<object> ClickCommand { get; set; }

    private void ClickAction(object parameter)
    {
        MessageBox.Show(parameter.ToString() + " dropdown menu item has been clicked");
    }
}

NOTE

View sample in GitHub. This sample showcases how to provide command binding for SplitButtonAdv control.