Full implementation of Relay Command - can it be applied to all cases?

前端 未结 1 638
梦谈多话
梦谈多话 2021-01-25 21:41

I\'m looking at the full implementation of a Relay Command that can be found here

I heard that the idea behind RelayCommand is to have a sort of \"universal remote contr

相关标签:
1条回答
  • 2021-01-25 22:14

    1) ICommand only has methods that include a parameter. If you don't specify a parameter in XAML, null is used.

    https://msdn.microsoft.com/en-us/library/system.windows.input.icommand(v=vs.110).aspx

    2) Yes, you can effect CanExecute without a CommandParameter. See below, it uses the viewmodel's string property "MyData" in CanExecute.

    MainWindow.xaml

    <Window x:Class="WpfApplication8.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:WpfApplication8"
            mc:Ignorable="d"
            FocusManager.FocusedElement="{Binding ElementName=tb}"
            SizeToContent="Height"
            Title="MainWindow" Width="525">
        <Window.DataContext>
            <local:MainWindowViewModel />
        </Window.DataContext>
        <StackPanel>
            <Label Content="MyData (CanExecute returns false if this is whitespace)" />
            <TextBox Name="tb" Text="{Binding MyData, UpdateSourceTrigger=PropertyChanged}" Margin="5" />
            <Button Content="Without XAML CommandParameter" Margin="5" Command="{Binding Command1}" />
            <Button Content="With XAML CommandParameter" Margin="5" Command="{Binding Command1}" CommandParameter="{Binding MyData}" />
        </StackPanel>
    </Window>
    

    MainWindow.xaml.cs

    using System;
    using System.ComponentModel;
    using System.Windows;
    using System.Windows.Input;
    
    namespace WpfApplication8
    {
        public partial class MainWindow : Window
        {
            public MainWindow()
            {
                InitializeComponent();
            }
        }
    
        public class MainWindowViewModel : INotifyPropertyChanged
        {
            private ICommand command1;
            public ICommand Command1 { get { return command1; } set { command1 = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Command1))); } }
    
            private string myData;
            public string MyData { get { return myData; } set { myData = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(MyData))); } }
    
            public event PropertyChangedEventHandler PropertyChanged;
    
            public MainWindowViewModel()
            {
                Command1 = new RelayCommand<object>(Command1Execute, Command1CanExecute);
            }
    
            private bool Command1CanExecute(object obj)
            {
                // Only allow execute if MyData has data
                return !string.IsNullOrWhiteSpace(MyData);
            }
    
            private void Command1Execute(object obj)
            {
                MessageBox.Show($"CommandParameter = '{obj}'");
            }
        }
    
        public class RelayCommand<T> : ICommand
        {
            #region Fields
    
            readonly Action<T> _execute = null;
            readonly Predicate<T> _canExecute = null;
    
            #endregion
    
            #region Constructors
    
            /// <summary>
            /// Initializes a new instance of <see cref="DelegateCommand{T}"/>.
            /// </summary>
            /// <param name="execute">Delegate to execute when Execute is called on the command.  This can be null to just hook up a CanExecute delegate.</param>
            /// <remarks><seealso cref="CanExecute"/> will always return true.</remarks>
            public RelayCommand(Action<T> execute)
                : this(execute, null)
            {
            }
    
            /// <summary>
            /// Creates a new command.
            /// </summary>
            /// <param name="execute">The execution logic.</param>
            /// <param name="canExecute">The execution status logic.</param>
            public RelayCommand(Action<T> execute, Predicate<T> canExecute)
            {
                if (execute == null)
                    throw new ArgumentNullException("execute");
    
                _execute = execute;
                _canExecute = canExecute;
            }
    
            #endregion
    
            #region ICommand Members
    
            ///<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)
            {
                return _canExecute == null ? true : _canExecute((T)parameter);
            }
    
            ///<summary>
            ///Occurs when changes occur that affect whether or not the command should execute.
            ///</summary>
            public event EventHandler CanExecuteChanged
            {
                add { CommandManager.RequerySuggested += value; }
                remove { CommandManager.RequerySuggested -= value; }
            }
    
            ///<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 <see langword="null" />.</param>
            public void Execute(object parameter)
            {
                _execute((T)parameter);
            }
    
            #endregion
        }
    }
    
    0 讨论(0)
提交回复
热议问题