数据和界面的交互离不开命令,命令离不开事件,一切的跳转一切的数据交换,皆来源于观察者

系统命令

System.Windows.Input.ICommand 连接数据与界面的桥梁
System.Windows.Input.RoutedCommand 原始桥梁
System.Windows.Input.RoutedUICommand 原始桥梁

ICommandSource InputBinding CommandBinding

自定义命令

    public class RelayCommand : ICommand
    {
        private readonly Action<object> _CanExecute;
        private readonly Action _Execute;

        public RelayCommand(Action execute)
        {
            _Execute = execute;
        }

        public RelayCommand(Action<object> execute)
        {
            _CanExecute = execute;
        }

        public event EventHandler CanExecuteChanged
        {
            add => CommandManager.RequerySuggested += value;
            remove => CommandManager.RequerySuggested -= value;
        }

        // 1.先判断命令是否可以执行(true)
        public bool CanExecute(object parameter)
        {
            return _CanExecute == null ? (_Execute == null ? false : true) : true;
        }
        // 2.若可以执行,则执行此方法,反之则跳过此方法
        public void Execute(object parameter)
        {
            if (parameter == null)
                _Execute?.Invoke();
            else
                _CanExecute?.Invoke(parameter);
        }
    }

触发器

NuGet Package : Microsoft.Xaml.Behaviors.Wpf

xmlns:i="http://schemas.microsoft.com/xaml/behaviors"

    <RadioButton
        Height="60"
        Content="{Binding TaskItem, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, NotifyOnSourceUpdated=True}"
        GroupName="ctl"
        IsChecked="{Binding IsTab, Mode=TwoWay}"
        Style="{StaticResource MahApps.Styles.RadioButton.Flat}">
        <i:Interaction.Triggers>
            <i:EventTrigger EventName="Checked">
                <i:InvokeCommandAction Command="{Binding DataContext.CheckedCmd, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ListView}, AncestorLevel=1}}" CommandParameter="{Binding}" />
            </i:EventTrigger>
        </i:Interaction.Triggers>
    </RadioButton>

    <Button Command="{Binding AddCmd}" Content="test" />

    <TextBlock
        Height="50"
        HorizontalAlignment="Stretch"
        Text="text">
        <i:Interaction.Triggers>
            <i:EventTrigger EventName="MouseDown">
                <i:InvokeCommandAction Command="{Binding MouseDownCmd}" />
            </i:EventTrigger>
        </i:Interaction.Triggers>
    </TextBlock>

快捷键命令

    <Window.InputBindings>
        <KeyBinding
            Key="T"
            Command="{Binding AltCmd}"
            Modifiers="Alt" />
    </Window.InputBindings>
    <Window.Resources>
        <RoutedUICommand x:Key="Cut" Text="剪切" />
    </Window.Resources>

    <Window.CommandBindings>
        <CommandBinding
            CanExecute="CommandBinding_CanExecute"
            Command="{StaticResource Cut}"
            Executed="CommandBinding_Cut" />
    </Window.CommandBindings>

    <Window.InputBindings>
        <KeyBinding Command="{StaticResource Cut}" Gesture="Ctrl+X" />
    </Window.InputBindings>

    private void CommandBinding_Cut(object sender, ExecutedRoutedEventArgs e)
    {
        vm?.CutCmd.Execute(e.Parameter);
    }
    //可省略此方法
    private void CommandBinding_CanExecute(object sender, CanExecuteRoutedEventArgs e)
    {
        e.CanExecute = true;
    }    

GalaMVVMlight

应用场景

基于自定义命令,分别在触发器和普通命令中的使用


    # 空参数
    private RelayCommand addCmd;
    public RelayCommand AddCmd
    {
        get
        {
            return addCmd ?? (addCmd = new RelayCommand(() =>
            {
            }));
        }
    }
    // 带参数
    private RelayCommand checkedCmd;
    public RelayCommand CheckedCmd
    {
        get
        {
            return checkedCmd ?? (checkedCmd = new RelayCommand(args =>
            {
                var node = args as TaskModel;
            }));
        }
    }    
    //快捷键命令
    private RelayCommand altCmd;
    public RelayCommand AltCmd
    {
        get
        {
            return altCmd ?? (altCmd = new RelayCommand(() =>
            {
                System.Diagnostics.Debug.WriteLine("");
            }));
        }
    }    
    //Cut
    private RelayCommand cutCmd;
    public RelayCommand CutCmd
    {
        get
        {
            return cutCmd ?? (cutCmd = new RelayCommand(() =>
            {
                System.Diagnostics.Debug.WriteLine("");
            }));
        }
    }    

过去面试中也会被问到此问题,还继续被问道 PreviewMouse 和 Mouse 的区别,隧道和冒泡

隧道 window -> top

冒泡 top -> window