WPF 入门笔记 - 06 - 命令
我们把世界看错,反说它欺骗了我们。 --飞鸟集
前言
相较而言,命令对我来说是一个新概念,因为在Winform
中压根没有所谓的命令这个概念??。从文字角度理解,"命令"可以指代一种明确的指令或要求,用于向某个实体传达特定的操作或行为。它可以是一个动词性的词语,表示对某个对象或主体的要求或指示。命令通常具有明确的目标和执行内容,它告诉接收者要执行什么操作,并在某种程度上对行为进行约束。
在软件开发中,"命令"是一种设计模式,它描述了将操作封装为对象的方法,以便在不同的上下文中使用和重用。这种命令模式通过将请求和操作封装到一个命令对象中,使得发送者和接收者之间解耦,从而实现了更灵活和可扩展的设计。在这种模式下,命令对象充当了发送者和接收者之间的中间媒介,接收者通过执行命令对象来完成特定的操作。
在提到命令的时候,我们通常拿它来和事件作比较。我们都知道,WPF
里已经有了路由事件,比如按钮在被点击以后做出的反应(直接事件),我们一般会通过Button
的Click
新建一个事件,然后在这个事件里面写一些业务代码:
private void Button_Click(object sender, RoutedEventArgs e)
{
MessageBox.Show("You click me.");
}
当我们运行程序点击按钮时,Button_Click
事件会被驱动响应点击的动作弹出一个消息对话框,没有问题对吧。我们都知道,在早期的GUI
框架中,应用程序的外观和行为方式之间没有真正的分离,回到这里也一样,将业务代码直接写在事件处理程序中会导致界面和业务逻辑紧密耦合在一起,使得两者难以分离和独立变更。实际开发中,我们会给按钮一个特定功能,当按钮的功能发生变化时,我们需要在UI
界面中修改与这个功能所绑定的东西,同时也需要调整业务代码,这就导致了界面元素(外观)和业务逻辑(行为)混在一起,使得按钮的XAML
代码既承担了外观的定义,又承担了业务逻辑的实现。此外,假设我们有很多个一样的按钮,都需要在用户点击按钮后为它提供相同的功能,通过上述面的方法,当这个功能发生改变时,我们就需要调正每一个涉及到的按钮以及相应的事件。为了解决这个问题,WPF
提供了命令机制(Command),可以将按钮的行为与其外观进行分离。
命令(Command)在WPF
中是一种用于处理用户界面交互的机制,它们提供了一种在界面元素(UI)和后台逻辑之间进行解耦的方式,使得交互操作可以以一种统一的、可重用的方式进行处理。WPF
命令的概念和实现是基于MVVM(Model-View-ViewModel)
架构模式的,它使得界面元素的交互操作可以通过命令对象进行管理和处理,而不需要直接在界面代码中编写事件处理程序。
通过使用命令,我们能够更好地组织和管理界面交互行为,使得代码结构清晰,易于维护和扩展。同时,命令还提供了一些额外的功能,如参数传递、命令的可用性控制等,使得我们能够更灵活地处理用户的操作。
事件和命令:
事件是与用户动作进行联动的,而命令是那些想要与界面分离的动作,比如常见的复制粘贴命令,当我们点击一个具有复制功能的按钮时,相当于我们通过点击的这个动作触发了一个复制的命令,这样做的好处就是 - 界面的交互操作变得简单、代码可重用性提高,在不破坏后台逻辑的情况下可以更加灵活的控制用户界面。
命令模型
WPF
命令模型主要包含以下几个基本元素:
命令(Command):指的是实现了ICommand
接口的类,例如RoutedCommand
类及其子类RoutedUICommand
类,一般不包含具体逻辑。
命令源(Command Source):即命令的发送者,指的是实现了ICommandSource
接口的类。像Button
、MenuItem
等界面元素都实现了这个接口,单击它们都会执行绑定的命令。
命令目标(Command Target):即命令的接受者,指的是实现了IInputElement
接口的类。
命令关联(Command Binding):即将一些外围逻辑和命令关联起来。
借用刘老师的图来看一下他们的关系:
ICommand
ICommand
接口,包含一个事件两个方法:
public interface ICommand
{
//
// 摘要:
// 当出现影响是否应执行该命令的更改时发生。
event EventHandler CanExecuteChanged;
// 摘要:
// 定义用于确定此命令是否可以在其当前状态下执行的方法。
//
// 参数:
// parameter:
// 此命令使用的数据。如果此命令不需要传递数据,则该对象可以设置为 null。
//
// 返回结果:
// 如果可以执行此命令,则为 true;否则为 false。
bool CanExecute(object parameter);
//
// 摘要:
// 定义在调用此命令时调用的方法。
//
// 参数:
// parameter:
// 此命令使用的数据。如果此命令不需要传递数据,则该对象可以设置为 null。
void Execute(object parameter);
}
反过来看:
-
Execute
- 执行某个动作 -
CanExecute
- 能不能执行动作 -
CanExecuteChanged
- 命令状态发生变化是响应的事件
通过实现ICommand
接口,我们可以创建自定义的命令对象,并将其与界面元素进行绑定。这样,界面元素就可以与命令相关联,通过调用命令的Execute
方法来执行具体的操作,而无需直接编写事件处理程序。
定义命令
下面我们试着用命令的方式来实现上面的点击事件,并逐步理解模型中的内容。我们新建一个类MainViewModel
来提供我们需要的功能方法:
using System.Windows;
namespace WPFDemo
{
public class MainViewModel
{
public void ShowInfo()
{
MessageBox.Show("You click me.");
}
}
}
ShowInfo()
这个时候跟UI
界面是分开的对吧,有了方法之后,我们可以说MainViewModel
中的ShowInfo
就命令了吗,根据模型来看显然还不行。继续走,写一个实现ICommand
接口但不带具体逻辑的类,比如CustomCommand
:
using System;
using System.Windows.Input;
namespace WPFDemo
{
public class CustomCommand : ICommand
{
private readonly Action _execute;
public CustomCommand(Action execute)
{
_execute = execute;
}
public event EventHandler CanExecuteChanged;
public bool CanExecute(object parameter)
{
// 在这里实现命令的可执行逻辑
return true; // 默认返回true,表示命令可执行
}
public void Execute(object parameter)
{
// 在这里实现命令的执行逻辑
_execute?.Invoke();
}
}
}
之后在MainViewModel
类中需要添加一个公共属性来暴露CustomCommand
实例作为ShowInfoCommand
,以便在XAML
中进行绑定;
using System.Windows;
namespace WPFDemo
{
public class MainViewModel
{
public CustomCommand ShowInfoCommand { get; set; }
public MainViewModel()
{
ShowInfoCommand = new CustomCommand(ShowInfo);
}
public void ShowInfo()
{
MessageBox.Show("You click me.");
}
}
}
最后,将CustomCommand
实例与界面元素进行绑定:
<Window x:Class="WPFDemo.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:WPFDemo"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
Title="MainWindow"
Width="800"
Height="450"
mc:Ignorable="d">
<Window.Resources>
<local:MainViewModel x:Key="ViewModel" />
</Window.Resources>
<Grid>
<Button Command="{Binding ShowInfoCommand}" Content="Click Me" DataContext="{StaticResource ViewModel}" />
</Grid>
</Window>
设置数据上下文也可以在后台代码中完成
回到命令模型上来,梳理以下对应关系:
CustomCommand
类本身是一个命令对象(ICommand
),它实现了命令接口,包括Execute
和CanExecute
方法。这个命令对象是命令模式中的 "具体命令"。MainViewModel
类作为命令的执行者(或者称为命令目标),其中包含了ShowInfo
方法。在命令模式中,执行者负责实际执行命令所需的操作。在我们的示例中,ShowInfo
方法是具体执行的业务逻辑。- 在
XAML
中,我们使用CommandBinding
将按钮的Click
事件与ShowInfoCommand
关联起来。这个关联是通过在Window
或UserControl
的CommandBindings
集合中添加一个新的CommandBinding
对象来完成的。这个CommandBinding
指定了ShowInfoCommand
作为命令和MainViewModel
作为命令的执行者。
注意:Command属性仅仅作为Click行为的绑定,其他行为,如鼠标移入、移出。。。等行为,要使用另外的
MVVM
方式进行绑定。
最后,梳理下程序结构,可以看到,我们分别在MainViewModel.cs
和MainWindow.xaml
中书写业务代码和逻辑。
通知更改
在WPF
中,实现属性的通知更改是通过实现 INotifyPropertyChanged
接口来实现的。这个接口定义了一个 PropertyChanged
事件,当属性的值发生变化时,可以通过触发该事件来通知界面进行更新。
在进行演示之前,先来看看我们上面所使用的例子能否像之前学习的绑定一样实现自动更新,按照业务分离的逻辑,我们在MainViewModel.cs
中添加一个Name
字段并在页面进行绑定。
MainViewModel.cs
:
using System.Windows;
namespace WPFDemo
{
public class MainViewModel
{
public CustomCommand ShowInfoCommand { get; set; }
public string Name { get; set; }
public MainViewModel()
{
Name = "狗熊岭第一狙击手";
ShowInfoCommand = new CustomCommand(ShowInfo);
}
public void ShowInfo()
{
Name = "光头强";
MessageBox.Show("You click me.");
}
}
}
MainWindow.xaml
:
<Window x:Class="WPFDemo.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:WPFDemo"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
Title="MainWindow"
Width="800"
Height="450"
WindowStartupLocation="CenterScreen"
mc:Ignorable="d">
<Window.DataContext>
<local:MainViewModel />
</Window.DataContext>
<Grid>
<StackPanel>
<Button Command="{Binding ShowInfoCommand}" Content="Click Me" />
<TextBox Text="{Binding Name}" />
</StackPanel>
</Grid>
</Window>
之前
xaml
中的数据上下文不太好,需要在每个控件中都定义一次??
上面的代码中,我们将Name
绑定到了TextBox
的文本中,并在点击按钮是改变Name
的值,如果它自己可以通知更改,自动更新的话那么在Name
变化的时候文本也应该变化,对吧。我们运行试一下:
可以看到Name
的变化时Text
并没有随之变化,这说明Name
发生改变以后并没有通知Text
也进行变化。如果你喜欢捣鼓的话,可以看看Text
如果被修改以后Name
会不会变化。
回到正题,上文提到过,实现属性的通知更改是通过实现 INotifyPropertyChanged
接口来实现的,我们来对自定义的MainViewModel.cs
稍作修改实现属性的通知更改:
using System.ComponentModel;
using System.Windows;
namespace WPFDemo
{
public class MainViewModel : INotifyPropertyChanged
{
public CustomCommand ShowInfoCommand { get; set; }
public event PropertyChangedEventHandler PropertyChanged;
private string _name;
public string Name
{
get { return _name; }
set
{
_name = value;
OnPropertyChanged(nameof(Name));
}
}
private void OnPropertyChanged(string name)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}
public MainViewModel()
{
Name = "狗熊岭第一狙击手";
ShowInfoCommand = new CustomCommand(ShowInfo);
}
public void ShowInfo()
{
Name = "光头强";
MessageBox.Show("You click me.");
}
}
}
??
nameof(Name)
是C# 6.0 引入的一个语法糖,它可以在编译时获取属性、方法、字段、类型等成员的名称作为一个字符串。在
WPF
中,nameof(Name)
用于在属性更改通知中指定属性的名称。它的作用是避免硬编码属性名称,从而减少在重构过程中出现由于重命名属性而导致的错误。
修改过后,MainViewModel
类实现了 INotifyPropertyChanged
接口,并在 Name
属性的 setter
中进行了属性更改通知。当 Name
属性的值发生变化时,会触发 PropertyChanged
事件,通知界面进行更新。
进阶玩法
在实现通知更改的方式中,可以将通知更改的逻辑定义在一个基类中,例如 ViewModelBase
类。这个基类可以包含通用的属性更改通知实现,以便其他具体的视图模型类可以继承该基类并重用这些通知更改的功能。
以下是一个简单的示例,展示了如何在 ViewModelBase
类中实现通知更改:
using System.ComponentModel;
using System.Runtime.CompilerServices;
namespace WPFDemo
{
public class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}
在上面的代码中,ViewModelBase
类实现了 INotifyPropertyChanged
接口,并提供了 OnPropertyChanged
方法用于触发属性更改通知事件,并将属性名称作为参数传递。
默认情况下,
CallerMemberName
特性用于自动获取调用该方法的成员的名称,并作为属性名称传递。
通过继承 ViewModelBase
类,并使用 OnPropertyChanged
方法来设置属性,可以简化视图模型类中属性更改通知的实现:
MainViewModel.cs
:
using System.Windows;
namespace WPFDemo
{
public class MainViewModel : ViewModelBase
{
public CustomCommand ShowInfoCommand { get; set; }
private string _name;
public string Name
{
get { return _name; }
set
{
_name = value;
OnPropertyChanged();
}
}
private string _description;
public string Description
{
get { return _description; }
set { _description = value; OnPropertyChanged(); }
}
public MainViewModel()
{
Name = "狗熊岭第一狙击手";
Description = "光头强";
ShowInfoCommand = new CustomCommand(ShowInfo);
}
public void ShowInfo()
{
Name = "光头强";
Description = "狗熊岭第一突破手,麦克阿瑟如是说。";
MessageBox.Show("You click me.");
}
}
}
在这个示例中,MainViewModel
类继承了 ViewModelBase
类,并使用 OnPropertyChanged
方法来设置 Name
属性。当 Name
属性的值发生更改时,SetProperty
方法会自动处理属性更改通知的逻辑,无需手动触发事件或编写重复的代码。
通过将通知更改的实现定义在基类中,可以实现更简洁、可维护和可重用的代码,避免在每个具体的视图模型类中重复编写通知更改的逻辑。
夹带私货 - 命令参数
有时候我们需要在执行命令时传递参数。在WPF中,可以使用CommandParameter
属性来传递参数给命令。
CommandParameter
是一个附加属性,可以将任意对象指定为命令的参数。当命令执行时,命令的Execute
方法会接收到该参数,并可以在命令处理逻辑中使用它。
以下是一个示例,展示如何在XAML
中为命令指定CommandParameter
:
<Button Content="Click Me" Command="{Binding MyCommand}" CommandParameter="Hello, World!" />
在这个示例中,我们将Button
的Command
属性绑定到MyCommand
命令。同时,我们通过CommandParameter
属性指定了一个字符串参数"Hello, World!"
。当点击按钮时,该参数将传递给MyCommand
命令的Execute
方法。
在命令的执行逻辑中,可以通过命令参数来获取传递的值。以下是一个简单的命令类示例:
CustomCommand.cs
:
using System;
using System.Windows.Input;
namespace WPFDemo
{
public class CustomCommand : ICommand
{
private readonly Action<object> _execute;
public CustomCommand(Action<object> execute)
{
_execute = execute;
}
public event EventHandler CanExecuteChanged;
public bool CanExecute(object parameter)
{
// 在这里实现命令的可执行逻辑
return true; // 默认返回true,表示命令可执行
}
public void Execute(object parameter)
{
// 在这里实现命令的执行逻辑
_execute?.Invoke(parameter as string);
}
}
}
CustomCommand
类接受一个 Action<object>
类型的参数,在构造函数中将传递的方法保存到 _execute
字段中。然后,在 Execute
方法中,通过调用 _execute?.Invoke(parameter)
来执行传递的方法,并将 parameter
作为参数传递给该方法。
这样,当你在 MainViewModel
中创建 CustomCommand
实例时,可以将 ShowInfo
方法作为参数传递进去,
MainViewModel.cs
:
using System.Windows;
namespace WPFDemo
{
public class MainViewModel
{
public CustomCommand ShowInfoCommand { get; set; }
public MainViewModel()
{
ShowInfoCommand = new CustomCommand(ShowInfo);
}
public void ShowInfo(object parameter)
{
MessageBox.Show(parameter as string);
}
}
}
那么ShowInfo(object parameter)
的参数从哪里来呢 - CommandParameter
附加属性:
<Window x:Class="WPFDemo.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:WPFDemo"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
Title="MainWindow"
Width="800"
Height="450"
WindowStartupLocation="CenterScreen"
mc:Ignorable="d">
<Window.DataContext>
<local:MainViewModel />
</Window.DataContext>
<Grid>
<StackPanel>
<Button Command="{Binding ShowInfoCommand}" Content="Click Me" CommandParameter="Hello, World!" />
</StackPanel>
</Grid>
</Window>
这样看上去可能比较蠢,我们可以些微调整一下在页面中完成显示内容的修改,代码就不贴了,大家应该知道:
通过命令参数,可以实现更灵活的命令处理逻辑,根据传递的参数来执行不同的操作。同时,使用命令参数也可以实现与界面元素的交互,例如根据按钮的点击位置传递坐标信息等。
MVVM
在文章开篇介绍命令时我们就有提到过WPF
命令的概念和实现是基于MVVM(Model-View-ViewModel)
架构模式的,而且从后续编码以及项目结构也可以看出来示例确实涉及了MVVM(Model-View-ViewModel)
的思想,下边我们来看一下具体什么是MVVM
以及一些主流的MVVM
框架的引用与使用方法。
MVVM
是一种软件架构模式,是Model(数据类型),View(界面),ViewModel(数据与界面之间的桥梁)的缩写,旨在将用户界面的逻辑与业务逻辑分离,以提高代码的可维护性、可测试性和可扩展性。
MVVM
模式由以下三个核心组件组成:
- Model(模型):模型代表应用程序的数据和业务逻辑。它独立于用户界面和视图模型,负责处理数据的获取、存储和处理等任务。
- View(视图):视图是用户界面的可视部分,负责展示数据和与用户的交互。它通常是
XAML
文件,描述了用户界面的布局和外观。视图应该只关注外观和布局,而不涉及具体的业务逻辑。 - ViewModel(视图模型):视图模型充当视图与模型之间的中介。它通过暴露命令和属性来向视图提供数据绑定和事件处理的功能。视图模型通过与模型交互获取和处理数据,并将处理后的数据以属性的形式提供给视图绑定。视图模型还负责处理用户交互,并将交互结果传递给模型进行处理。
MVVM
模式的优势在于它实现了界面逻辑和业务逻辑的分离,使得代码更加清晰、可维护和可测试,视图和视图模型的解耦使得可以独立开发和测试它们,同时也提供了更好的可扩展性,使得可以在不影响视图的情况下修改和增加业务逻辑。
总结起来,MVVM
模式通过将用户界面、数据和业务逻辑进行分离,提供了一种结构化的方式来开发和维护WPF
应用程序。它使得开发人员能够更好地管理代码,并使得应用程序更具可扩展性和可测试性。
构建MVVM
框架时有自己造轮子的,就像上面命令的示例中那样;也有使用现成的开源项目,下面例举两个比较常见的现成的框架包。
MvvmLight
项目地址:mvvmlight
MVVM Light is not maintained anymore. Over the years, thousands of users have found this project useful with millions of downloads. We are truly overwhelmed by the kindness shown by a huge amount of members of this awesome community. Thanks so much for making this little project so popular and for making it all worthwhile.
MvvmLight
不再维护。多年来,成千上万的用户发现这个项目有数百万的下载量。我们真的被这个令人敬畏的社区的大量成员所表现出的善意所淹没。非常感谢你让这个小项目如此受欢迎,让它一切都变得有价值。
We strongly recommend looking into the Microsoft MVVM Toolkit, an open source project from the Windows Community Toolkit, as the successor of MVVM Light.
我们强烈建议研究Microsoft MVVM Toolkit,这是Windows社区工具包中的一个开源项目,作为MVVM Light的继任者。
MvvmLight
是一个轻量级的 MVVM
框架,它提供了许多用于实现 MVVM
模式的工具和功能。以下是 MvvmLight
的一些主要特点和组成部分:
ViewModel
基类:MvvmLight
提供了一个称为ViewModelBase
的基类,用于派生自定义的视图模型类。这个基类实现了INotifyPropertyChanged
接口,简化了属性更改通知的实现,并提供了一些其他实用的功能。- 事件聚合器(Event Aggregator):
MvvmLight
提供了一个事件聚合器,用于实现视图模型之间的松耦合通信。视图模型可以发布事件,其他视图模型可以订阅并响应这些事件,实现了解耦的消息传递机制。 - 命令实现:
MvvmLight
提供了RelayCommand
类,它是一个通用的实现了ICommand
接口的命令类。通过使用RelayCommand
,开发人员可以轻松地在视图模型中定义和执行命令,并与视图进行绑定。 - 消息传递:
MvvmLight
提供了一个消息传递机制,允许视图模型之间进行简单的消息通信。开发人员可以发送消息并订阅消息,以实现视图模型之间的通信和交互。 - 服务定位器(Service Locator):
MvvmLight
提供了一个简单的服务定位器,用于解耦视图模型和具体的服务实现。通过使用服务定位器,视图模型可以轻松地获取所需的服务实例,而不需要直接实例化服务类。
MvvmLight
是一个功能丰富且易于使用的 MVVM
框架,它提供了许多有用的工具和功能,帮助开发人员更轻松地实现 MVVM
模式,接下来我们试一试将MvvmLight
框架应用在我们昨天的例子中。
在项目中添加MvvmLight
的NuGet包,以便引入MvvmLight
框架的相关组件和功能,对应版本安装就行了,注意区分自己的项目是在.Net Framework
框架下还是.Net Core
:
安装完以后可以看到,项目的结构会发生些许变化,它会自动创建了一个名为ViewModel
的文件夹以及MainViewModel.cs
、ViewModelLocator.cs
文件,同时App.xaml
文件也会发生变化:
-
MainViewModel.cs
- 继承自由MvvmLight
框架提供的ViewModelBase
类,ViewModelBase
类又继承类ObservableObject
,同时实现了ICleanup
接口,而ObservableObject
类实现了INotifyPropertyChanged
接口,用于通知属性的改变,需要时调用RaisePropertyChanged()
即可。 -
ViewModelLocator.cs
- 文件中只有一个ViewModelLocator
类,类中包括一个构造函数、一个类型为MainViewModel
的Main
属性、以及一个静态的Cleanup
函数。在构造函数中,创建了一个SimpleIoc
类型的单实例,用于注册MainViewModel
,然后用ServiceLocator
对这个SimpleIoc
类型的单实例进行包裹,方便统一管理。 -
App.xaml
文件变化 -ViewModelLocator
类被生成资源字典并加入到了全局资源。 -
DataContext="{Binding Main, Source={StaticResource Locator}}"
安装完成以后,我们把之前我们自造的MVVM
模式的文件从项目排除,在生成的MainViewModel.cs
编写之前的业务逻辑代码:
ViewModel\MainViewModel.cs
:
using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Command;
using System.Windows;
namespace WPFDemo.ViewModel
{
public class MainViewModel : ViewModelBase
{
public RelayCommand<object> ShowInfoCommand { get; }
public string _name;
public string Name
{
get { return _name; }
set { _name = value; RaisePropertyChanged(); }
}
public string _description;
public string Description
{
get { return _description; }
set { _description = value; RaisePropertyChanged(); }
}
public MainViewModel()
{
Name = "菠萝吹雪";
Description = "哦,尊严,多少钱一斤哪。";
ShowInfoCommand = new RelayCommand<object>(ShowInfo);
}
public void ShowInfo(object parameter)
{
Name = parameter as string;
Description = parameter as string;
MessageBox.Show(parameter as string);
}
}
}
MainWindow.xaml
:
<Window x:Class="WPFDemo.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:WPFDemo"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
Title="MainWindow"
Width="800"
Height="450"
DataContext="{Binding Main, Source={StaticResource Locator}}"
WindowStartupLocation="CenterScreen"
mc:Ignorable="d">
<Grid>
<StackPanel>
<TextBox Height="30" Text="{Binding Name}" />
<TextBox Height="30" Text="{Binding Description}" />
<TextBox x:Name="textBox"
Height="30"
Text="Hello,World!" />
<Button Command="{Binding ShowInfoCommand}"
CommandParameter="{Binding ElementName=textBox, Path=Text}"
Content="Click Me" />
</StackPanel>
</Grid>
</Window>
运行程序:
CommunityToolkit.Mvvm
CommunityToolkit.Mvvm
包(又名 MVVM
工具包,以前名为 Microsoft.Toolkit.Mvvm
)是一个现代、快速且模块化的 MVVM
库。
??没有
.Net Framework
的版本,本章终。。。
Done
在WPF
中,命令是一种用于处理用户交互操作的机制。它将操作行为与界面元素解耦,使得界面元素可以通过命令进行触发和执行相应的逻辑。WPF
中的命令模型通过ICommand
接口和相关的实现类来实现。命令模式的设计思想是将命令的发送者(例如按钮)与命令的执行者(例如视图模型中的方法)解耦,使得它们之间不直接依赖,提高代码的可维护性和重用性。
MVVM(Model-View-ViewModel)
是一种用于构建WPF
应用程序的软件架构模式,它将应用程序的逻辑分为三个核心部分:模型、视图和视图模型。模型表示数据模型,负责数据的获取和处理;视图表示用户界面,负责界面的展示;视图模型是视图和模型之间的桥梁,负责处理业务逻辑、提供数据绑定和命令等功能。MVVM
通过数据绑定和命令的方式实现视图和视图模型的通信,将界面逻辑和业务逻辑分离,使得代码更加清晰、可测试和可维护。