自学内容网 自学内容网

WPF命令

一、命令模型

WPF命令模型具有如下4个重要元素:

命令:命令表示应用程序任务,并且跟踪任务是否能够执行。然而,命令实际上不包含执行应用程序任务的代码。
命令绑定:每个命令绑定针对用户界面的具体局域,将命令连接到相关的应用程序逻辑。这种分解的设计非常重要,因为单个命令可用于应用程序中的多个地方,并且在每个地方具有不同的意义。为处理这一问题,需要将统一命令与不同的命令绑定。
命令源:命令源触发命令。例如,MenuItem 和 Button 都是命令源,单击它们都会执行绑定命令。
命令目标:命令目标是在其中执行命令的元素。根据命令的本质,目标可能很重要,也可能不重要。

二、命令库

WPF提供了基本的命令库,基本命令库中保存的命令超过100条。这些命令通过一下5个专门的静态类的静态属性提供:

ApplicationCommands:该类提供了通用命令,包括剪贴板命令(Copy、Cut、Paste)以及文档命令(New、Open、Save、Save As、Print等)。
NavigationCommands:该类提供了用于导航的命令,包括为基于页面的应用程序设计的一些命令(BrowseBack、BrowseForward、NextPage),以及其他适合于基于文档的应用程序的命令(IncreaseZoom、Refresh)。
EditingCommands:该类提供了许多重要的文档编辑命令,包括用于移动的命令(MoveToLineEnd、MoveLeftByWord、MoveUpByPage等),选择内容的命令(SelectToLineEnd、SelectLeftByWord),以及改变格式的命令(ToggleBold、ToggleUnderLine)。
ComponentCommands:该类提供了由用户界面组件使用的命令,包括用于移动和选择内容的命令,这些命令和 EditingCommands类中一些命令类似(甚至完全相同)。
MediaCommands:该类提供了一组用于处理多媒体的命令(如Play、Pause、NextTrack以及IncreaseVolume)。

三、命令源

命令库中的命令始终可用。触发它们的最简单方法就是将它们关联到实现了 ICommandSource接口的控件,大多数是类似按钮类的控件

ICommandSource接口定义了三大属性:

Command指向连接的命令,这是唯一必须的细节
CommandParameter提供其他希望随命令发送的数据
CommandTarget确定将在其中执行命令的元素
<Button Command="ApplicationCommands.New" Content="New"/>

四、命令绑定

当将命令关联到命令源时,由于命令还没有与其关联的绑定,所有按钮被认为是禁用的,通过控制 IsEnabled 属性。

为改变这种状态,需要为命令创建绑定以明确以下三件事情:

  • 当命令被触发时执行什么操作
  • 如何确定命令是否能够被执行(可选,默认总是可用)
  • 命令在何处起作用。例如命令可被限制在单个按钮中使用或在整个窗口中
<Window x:Class="WpfApp3.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:WpfApp3"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Window.CommandBindings>
        <CommandBinding Command="ApplicationCommands.New" Executed="CommandBinding_Executed"/>
    </Window.CommandBindings>
    <Grid>
        <Button Command="ApplicationCommands.New" Content="New"/>
    </Grid>
</Window>

通过代码创建绑定:

public MainWindow()
{
    InitializeComponent();
 
    CommandBinding commandBinding = new CommandBinding(ApplicationCommands.New);
    commandBinding.Executed += CommandBinding_Executed;
    this.CommandBindings.Add(commandBinding);
}

PS: 如是在CommandBindings中添加两个New命令,Button触发时只会触发第一个New命令Executed的事件。

五、自定义命令

namespace WpfApp3
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.Windows.Input;
 
    public class DataCommands
    {
        public static RoutedUICommand Requery { get; private set; }
 
        static DataCommands()
        {
            InputGestureCollection inputs = new InputGestureCollection();
            inputs.Add(new KeyGesture(Key.R, ModifierKeys.Control, "Ctrl+R"));
            Requery = new RoutedUICommand("Requery", nameof(Requery), typeof(DataCommands), inputs);
        }
    }
}
<Window x:Class="WpfApp3.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:local="clr-namespace:WpfApp3" 
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
        Title="MainWindow" Width="800" Height="450" mc:Ignorable="d">
    <Window.CommandBindings>
        <CommandBinding Command="ApplicationCommands.New" Executed="CommandBinding_Executed" />
        <CommandBinding Command="local:DataCommands.Requery" Executed="CommandBindingRequery_Executed" />
    </Window.CommandBindings>
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition />
            <RowDefinition />
        </Grid.RowDefinitions>
        <Button Command="ApplicationCommands.New" Content="New" />
        <TextBox Grid.Row="1" />
    </Grid>
</Window>

这个时候在窗体的任何地方按下 Ctrl+R都会触发Requery命令。

1.CommandParameter

<Window x:Class="WpfApp3.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:local="clr-namespace:WpfApp3" 
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
        Title="MainWindow" Width="800" Height="450" mc:Ignorable="d">
    <Window.CommandBindings>
        <CommandBinding Command="ApplicationCommands.New" Executed="CommandBinding_Executed" />
        <CommandBinding Command="local:DataCommands.Requery" Executed="CommandBinding_Executed_2" />
    </Window.CommandBindings>
    <StackPanel>
        <Button Command="ApplicationCommands.New" Content="New"/>
        <Button x:Name="btn1" Command="local:DataCommands.Requery" CommandParameter="1" Content="New"/>
        <Button x:Name="btn2" Command="local:DataCommands.Requery" CommandParameter="2" Content="Copy" />
    </StackPanel>
</Window>
namespace WpfApp3
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Data;
    using System.Windows.Documents;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Media.Imaging;
    using System.Windows.Navigation;
    using System.Windows.Shapes;
 
    /// <summary>
    /// MainWindow.xaml 的交互逻辑
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }
 
        private void CommandBindingRequery_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            MessageBox.Show($"CommandBinding_Executed_2===>{e.Parameter}===>{e.Source}===>{e.OriginalSource}==>{e.Command}");
        }
    }
}
  • 当我们在按钮上通过快捷键 Ctrl+R 触发命令时,sender=Window,e.OriginalSource=Window,e.Parameter=n
  • 当我们单击btn1时,sender=Window,e.OriginalSource=btn1,e.Parameter=1
  • 当我们单击btn2时,sender=Window,e.OriginalSource=btn2,e.Parameter=2

2.CommandTarget

<Window x:Class="WpfApp3.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:local="clr-namespace:WpfApp3" 
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
        Title="MainWindow" Width="800" Height="450" mc:Ignorable="d">
    <Window.CommandBindings>
        <CommandBinding Command="ApplicationCommands.New" Executed="CommandBinding_Executed" />
        <CommandBinding Command="local:DataCommands.Requery" Executed="CommandBinding_Executed_2" />
    </Window.CommandBindings>
    <StackPanel>
        <Button Command="ApplicationCommands.New" Content="New"/>
        <Button x:Name="btn1" Command="local:DataCommands.Requery" CommandParameter="1" Content="New" CommandTarget="{Binding ElementName=btn2}"/>
        <Button x:Name="btn2" Command="local:DataCommands.Requery" CommandParameter="2" Content="Copy" />
    </StackPanel>
</Window>
  • 当我们在按钮上通过快捷键 Ctrl+R 触发命令时,sender=Window,e.OriginalSource=Window,e.Parameter=null
  • 当我们单击btn1时,sender=Window,e.OriginalSource=btn2,e.Parameter=1
  • 当我们单击btn2时,sender=Window,e.OriginalSource=btn2,e.Parameter=2

六、ViewModel Command

namespace WpfApp3
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.Windows.Input;
 
    public class RelayCommand : ICommand
    {
        public event EventHandler CanExecuteChanged
        {
            add
            {
                if (_canExecute != null)
                {
                    CommandManager.RequerySuggested += value;
                }
            }
            remove
            {
                if (_canExecute != null)
                {
                    CommandManager.RequerySuggested -= value;
                }
            }
        }
 
        public bool CanExecute(object parameter)
        {
            if (_canExecute != null)
            {
                return _canExecute(parameter);
            }
            return true;
        }
 
        public virtual void Execute(object parameter)
        {
            if (_execute != null && CanExecute(parameter))
            {
                _execute(parameter);
            }
        }
 
        Action<object> _execute;
        Func<object, bool> _canExecute;
 
        public RelayCommand(Action<object> execute) : this(execute, null)
        {
        }
 
        public RelayCommand(Action<object> execute, Func<object, bool> canExecute)
        {
            _execute = execute;
            _canExecute = canExecute;
        }
 
        public void RaiseCanExecuteChanged()
        {
        }
 
    }
}
namespace WpfApp3
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
 
    public class ViewModel
    {
 
        public string Name { get; set; }
        public int Age { get; set; }
 
        public RelayCommand Update { get; private set; }
 
        public ViewModel()
        {
            Update = new RelayCommand(update);
        }
 
        void update(object param)
        {
 
        }
    }
}
<Window x:Class="WpfApp3.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:local="clr-namespace:WpfApp3" 
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
        Title="MainWindow" Width="800" Height="450" mc:Ignorable="d" d:DataContext="{d:DesignInstance Type=local:ViewModel}">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition />
            <RowDefinition />
            <RowDefinition />
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition/>
            <ColumnDefinition/>
        </Grid.ColumnDefinitions>
        <TextBlock Text="Name:"/>
        <TextBox Text="{Binding Name}" Grid.Column="1"/>
 
        <TextBlock Text="Age:" Grid.Row="1" Grid.Column="0"/>
        <TextBox Text="{Binding Age}" Grid.Row="1" Grid.Column="1"/>
 
        <Button Command="{Binding Update}" Grid.Row="2" Grid.ColumnSpan="2" Content="Update" CommandParameter="8"/>
    </Grid>
</Window>


原文地址:https://blog.csdn.net/hccee/article/details/143744024

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!