WPF自定义命令
在实际的编程工作中,我们可以只是用事件,不用命令,程序的逻辑也一样被驱动的很好,但我们不能阻止程序员按照自己的习惯去写代码。比如保存事件的处理器,程序员们可以写Save()、Savehandler()、SaveDocument()...这些都符合代码规范,但是迟早有一天整个项目会变得无法读懂,新来的程序员或者修改bug的程序员会很抓狂。
WPF命令简介
WPF的命令是实现了ICommand接口的类。ICommand接口非常简单,只包含两个方法和一个事件。
- Execute方法:命令执行,或者说命令作用于目标之上。
- CanExecute方法:在执行之前来弹指命令是否可被执行。
- CanExecuteChanged事件:当命令执行状态发生改变时,可激发此事件来通知其他对象。
RoutedCommand就是这样一个实现了ICommand接口的类。RoutedCommand在实现ICommand接口时,并未向其中添加任何逻辑。
WPF的命令系统由几个基本元素构成,他们是:
- 命令:WPF命令实际上就是实现了ICommand接口的类,平时使用最多的是RoutedCommand类。
- 命令源:即命令的发送者,是实现了ICommandSource接口的类。
- 命令目标:即命令将推送给谁,或者说命令将作用在谁身上。命令目标是必须实现了IInputElement接口的类。
- 命令关联:负责把一些外围逻辑与命令关联起来,比如执行之前对命令是否可执行进行判断、命令执行后还有那些后续工作等。
命令具有一处声明处处可用的特点,因此,MS在WPF类库里准备而来一些便捷的命令库,例如:
下面分别用WPF命令库,和自定义命令实现同样的功能。
WPF命令库命令
Demo程序的UI如下:
<Window x:Class="WPFCommand.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="MainWindow" Height="350" Width="525"> <Window.CommandBindings> <CommandBinding Command="New" CanExecute="CommandBinding_CanExecute" Executed="CommandBinding_Executed"/> </Window.CommandBindings> <Grid> <Grid.RowDefinitions> <RowDefinition /> <RowDefinition /> <RowDefinition /> <RowDefinition /> <RowDefinition /> </Grid.RowDefinitions> <DockPanel Height="60" Grid.Row="0"> <TextBlock VerticalAlignment="Center" Text="Name:" DockPanel.Dock="Left" Width="100" FontSize="30" Foreground="PaleVioletRed"/> <TextBox x:Name="txtName" DockPanel.Dock="Right" FontSize="40"/> </DockPanel> <Button Command="New" CommandParameter="Teacher" Content="New Teacher" Grid.Row ="1"/> <Button Command="New" CommandParameter="Student" Content="New Student" Grid.Row ="2"/> <ListBox x:Name="listBox1" Grid.Row="3" Grid.RowSpan="2"/> </Grid> </Window>
后台代码如下:
using System.Windows; using System.Windows.Input; namespace WPFCommand { /// <summary> /// MainWindow.xaml 的交互逻辑 /// </summary> public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); } private void CommandBinding_CanExecute(object sender, CanExecuteRoutedEventArgs e) { if (string.IsNullOrWhiteSpace(txtName.Text)) { e.CanExecute = false; } else { e.CanExecute = true; } } private void CommandBinding_Executed(object sender, ExecutedRoutedEventArgs e) { string name = txtName.Text; if (e.Parameter.ToString() == "Teacher") { listBox1.Items.Add("New Teacher: "+name); } if (e.Parameter.ToString() == "Student") { listBox1.Items.Add("New Student: "+name); } } } }
程序的运行结果如下:
当txtName.Text为WhiteSpace时,命令不可被执行。
执行后效果如下:
前面说过不用命令,程序的逻辑也可以被驱动的很好。且在一般情况下,在程序中使用与逻辑无关的RoutedCommand来跑跑龙套也就足够了,上面这个命令用的就有十足的“酱油”的嫌疑。
OK,把打酱油进行到底吧,下面自定义一个命令,实现相同的功能。
WPF自定义命令
注意对比前面使用命令库命令的方法异同。
程序的UI如下:
<Window x:Class="MyCommand.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="My Command Window" Height="350" Width="525" x:Name="mainWindow" > <Grid > <Grid.RowDefinitions> <RowDefinition /> <RowDefinition /> <RowDefinition /> <RowDefinition /> <RowDefinition /> </Grid.RowDefinitions> <DockPanel Height="60" Grid.Row="0"> <TextBlock VerticalAlignment="Center" Text="Name:" DockPanel.Dock="Left" Width="100" FontSize="30" Foreground="PaleVioletRed"/> <TextBox x:Name="txtName" DockPanel.Dock="Right" FontSize="40"/> </DockPanel> <Button CommandParameter="Teacher" x:Name="button1" Content="New Teacher" Grid.Row ="1"/> <Button CommandParameter="Student" x:Name="button2" Content="New Student" Grid.Row ="2"/> <ListBox x:Name="listBox1" Grid.Row="3" Grid.RowSpan="2"/> </Grid> </Window>
后台代码如下:
using System.Windows; using System.Windows.Input; namespace MyCommand { /// <summary> /// MainWindow.xaml 的交互逻辑 /// </summary> public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); // InitCmd(); } //声明并定义命令 private RoutedCommand newCmd=new RoutedCommand ("NewTS",typeof(MainWindow )); private void InitCmd() { //创建命令关联 CommandBinding cb = new CommandBinding(); cb.Command = newCmd; cb.CanExecute += new CanExecuteRoutedEventHandler(CanExecute1); cb.Executed += new ExecutedRoutedEventHandler(Executed1); //把命令关联安置在外围控件上 mainWindow.CommandBindings.Add(cb); //把命令赋值给命令源(发送者) button1.Command = newCmd; button2.Command = newCmd; } private void CanExecute1(object sender,CanExecuteRoutedEventArgs e) { //e.CanExecute = true; if (string.IsNullOrWhiteSpace(txtName.Text)) { e.CanExecute = false; } else { e.CanExecute = true; } } private void Executed1(object sender, ExecutedRoutedEventArgs e) { string name = txtName.Text; if (e.Parameter.ToString() == "Teacher") { listBox1.Items.Add("New Teacher: " + name); } if (e.Parameter.ToString() == "Student") { listBox1.Items.Add("New Student: " + name); } } } }
程序的运行效果和上面的相同:
当txtName.Text为WhiteSpace时,命令不可被执行。
执行后效果如下:
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 25岁的心里话
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器