切换导航
简历
工具
演示
查询
导航菜单
服务端
30
前端
114
数据库
82
进阶开发
8
桌面程序
2
QA
15
软件使用
36
规范协议
5
操作系统
11
AI
0
复用资源
6
硬件
0
标签
WPF
winfrom
外部链接
.NET Core SDK和运行时安装包
淘宝 NPM 镜像
查询网
Tables Generator线上表格转换工具
引用cdn在线脚本和样式
首页
桌面程序
WPF 元素、控件属性绑定变量、命令,使用MVVM思想进行绑定
[TOC] ## 1. XAML元素/控件属性绑定 在 WPF 开发中为了将视图开发和后端业务开发分开,WPF 提供了绑定的方法,只要视图(XAML)绑定的变量与后端定义的变量名字一致,就能实现双向绑定。随着绑定的优点的凸显,随之WPF就有了 MVVM 开发思想,M 模型(数据对象),V 视图界面,VM 处理视图(V)与模型(M)之间的业务,本文此章节主要是属性绑定相关的内容 ### 1.1. 元素/控件的属性绑定变量(属性) 页面(XAML)编辑了一个文本框,文本框的 Text 绑定了一个属性,绑定需要使用了一个关键字 `Binding`,绑定的属性是 `UserName` ```XML <TextBox Grid.Row="0" Grid.Column="1" Height="30" Margin="5" Text="{Binding UserName}"/> ``` 后端cs页面定义了一个属性 `UserName`,这样只要页面上文本框输入了信息,后端就可以获取到文本框输入的值了 ```csharp public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); //上下文为本页面cs代码(这里很关键,只有明确了上下文的指向才能实现绑定) DataContext = this; } public string UserName {get;set;} // 方法绑定到一个按钮点击事件上 public void GetInputValue{ MessageBox.Show(UserName); } } ``` > **特别说明:**XAML控件上绑定的属性/变量名称必须与后端cs文件上声明的一致 ### 1.2. 元素/控件的双向绑定 要做到控件的双向绑定需要实现 `INotifyPropertyChanged` 接口的 `PropertyChangedEventHandler` 事件,通过监听属性值的变化做到通知页面的实现,下面是一个基础的示例 ```csharp public class MainWindow : INotifyPropertyChanged public event PropertyChangedEventHandler PropertyChanged; // propertyName 是属性的名字,固定的写法 public void RaisePropertyChanged(string propertyName) { var handler = PropertyChanged; if (handler != null) { handler(this, new PropertyChangedEventArgs(propertyName)); } } } ``` 通知事件已经实现了,下面是调用方式,下面的代码同样是放在 MainWindow 类下面 ```csharp // 这里是一个完整的属性写法 public string _userName; public string UserName { get { return _userName; } set { _userName = value; RaisePropertyChanged("UserName"); //这里就使用了上面的事件,当属性发生变化时就会通知到页面 } } ``` 同样在页面上需要一个控件来绑定上面的 `UserName` 属性 ```XML <TextBox Grid.Row="0" Grid.Column="1" Height="30" Margin="5" Text="{Binding UserName}"/> ``` ### 1.3. MVVM 编程思想处理数据的绑定 MVVM的思想指的是将视图(V),数据模型(M)和视图模型(VM),分离出来,视图模型专门处理数据的业务,负责将模型(M)中的数据转换成视图(V)可以展示的格式,并实现了视图和模型之间的双向绑定 #### 1.3.1. 基础的MVVM示例 + **1.** 创建一个页面(MainWindow.xaml),页面上有两个输入文本,它的XAML如下:<br> ```XML <TextBlock Grid.Row="0" Grid.Column="0" Text="用户名:" Margin="5" HorizontalAlignment="Right" VerticalAlignment="Center"></TextBlock> <TextBox Grid.Row="0" Grid.Column="1" Height="30" Margin="5" Text="{Binding UserName}"/> <TextBlock Grid.Row="1" Grid.Column="0" Text="密码:" Margin="5" HorizontalAlignment="Right" VerticalAlignment="Center"></TextBlock> <TextBox Grid.Row="1" Grid.Column="1" Height="30" Margin="5" Text="{Binding Password}"/> <Button Margin="5" HorizontalAlignment="Left" Width="100" Height="30" Content="登录" Background="DarkOrange" BorderBrush="Black" Foreground="White" FontSize="15" Click="ShowMessage"></Button> ``` + **2.** 创建对应的数据模型(MainWindowModel.cs),模型内的属性对应页面上两个输入文本<br> ```csharp public class MainWindowModel { public string _userName; public string UserName { get { return _userName; } set { _userName = value; } } public string _password; public string Password { get { return _password; } set { _password = value; } } } ``` + **3.** 创建对应的视图模型(MainWindowVMModel.cs),模型内的属性对应页面上两个绑定的属性并且命名必须是一致的,因为在这个示例中页面上绑定的属性就是指向这个VM模型上的属性,在视图模型(VM)上同时也要实现 `INotifyPropertyChanged` 接口的 `PropertyChangedEventHandler` 事件,后续的数据双向绑定的业务也是在这个视图模型(VM)中处理的<br> ```csharp public class MainWindowVMModel : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; public void RaisePropertyChanged(string propertyName) { var handler = PropertyChanged; if (handler != null) { handler(this, new PropertyChangedEventArgs(propertyName)); } } // 这里需要注意的是视图模型(VM)并不保存数据,它指向的都是数据模型,在视图模型(VM)中的属性起到一个暴露的作用,用来处理数据的双向绑定 MainWindowModel model = new MainWindowModel(); public string UserName { get { return model.UserName; } set { model.UserName = value; RaisePropertyChanged("UserName"); } } public string Password { get { return model.Password; } set { model.Password = value; RaisePropertyChanged("Password"); } } } ``` + **4.** 视图数据双向绑定上下文明确,在视图的cs(MainWindow.xaml.cs)文件下处理<br> ```csharp public partial class MainWindow : Window { MainWindowVMModel model; public MainWindow() { InitializeComponent(); // 这里上下文绑定的数据是视图模型(VM)而不是数据模型 DataContext = model = new MainWindowVMModel(); } // 这里通过一个按钮事件来确定数据绑定情况,满足下面两个条件即双向绑定成功 // 1、有获取到数据 // 2、数据匹对不成功情况模型数据,页面文本框信息也清空了 private void ShowMessage(object sender, RoutedEventArgs e) { if (model.UserName == "wpf" && model.Password == "123") { MessageBox.Show("中国人民万岁!"); } else { MessageBox.Show("你好!中国"); model.UserName = model.Password = ""; } } } ``` ## 2. XAML元素/控件的命令绑定 在WPF中控件除了提供事件来与后端代码交互外,还提供了一种绑定命令的方式来实现与后端代码的交互,但是要将页面上的元素/控件与命令绑定需要实现一个接口 `ICommand`,实现 `ICommand` 接口需要实现接口下面的两个方法(CanExecute、Execute)和一个事件(CanExecuteChanged),下面是一个基础的实现示例 ```csharp public class RelayCommand : ICommand { // 通过委托将要执行的业务方法传入到此实现中 readonly Action execute; // 命令执行的方法 readonly Func<bool> canExecute; // 是否执行命令 public RelayCommand(Action _execute, Func<bool> _canExecute) { execute = _execute; canExecute = _canExecute; } // ICommand接口中要实现的方法,是否执行命令 public bool CanExecute(object parameter) { if (canExecute == null) { return true; } return canExecute(); } // ICommand接口中要实现的方法,命令需要执行的方法 public void Execute(object parameter) { execute(); } // ICommand接口中要实现的事件,追加和删除事件 public event EventHandler CanExecuteChanged { add { CommandManager.RequerySuggested += value; } remove { CommandManager.RequerySuggested -= value; } } } ``` ### 2.1. 使用MVVM的方式绑定命令 这里延用本文 [1.3.1.基础的MVVM示例](#h4-1-3-1-mvvm-) 章节的示例,对其进行改造,下面直接上示例 + **1.** 在视图模型(VM)中追加声明命令和命令执行的方法<br> ```csharp public class MainWindowVMModel : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; public void RaisePropertyChanged(string propertyName) { var handler = PropertyChanged; if (handler != null) { handler(this, new PropertyChangedEventArgs(propertyName)); } } MainWindowModel model = new MainWindowModel(); public string UserName { get { return model.UserName; } set { model.UserName = value; RaisePropertyChanged("UserName"); } } public string Password { get { return model.Password; } set { model.Password = value; RaisePropertyChanged("Password"); } } //命令执行的具体方法 void Login() { if (UserName == "wpf" && Password == "123") { MessageBox.Show("中国人民万岁!"); } else { MessageBox.Show("你好!中国"); UserName = Password = ""; } } // 是否执行命令,这里肯定是要执行,也没什么业务直接写死 bool canExecute() { return true; } // 控件绑定的命令 public ICommand SubLogin { get { // 这里使用到上面ICommand接口的实现 return new RelayCommand(Login, canExecute); } } } ``` + **2.** 修改页面(MainWindow.xaml)控件,使用 Command 绑定命令,使用 Command 替换了 Click 事件<br> ```xml <TextBlock Grid.Row="0" Grid.Column="0" Text="用户名:" Margin="5" HorizontalAlignment="Right" VerticalAlignment="Center"></TextBlock> <TextBox Grid.Row="0" Grid.Column="1" Height="30" Margin="5" Text="{Binding UserName}"/> <TextBlock Grid.Row="1" Grid.Column="0" Text="密码:" Margin="5" HorizontalAlignment="Right" VerticalAlignment="Center"></TextBlock> <TextBox Grid.Row="1" Grid.Column="1" Height="30" Margin="5" Text="{Binding Password}"/> <Button Margin="5" HorizontalAlignment="Left" Width="100" Height="30" Content="登录" Background="DarkOrange" BorderBrush="Black" Foreground="White" FontSize="15" Command="{Binding SubLogin}"></Button> ``` + **3.** 使用命令绑定之后,页面上的后台代码(MainWindow.xaml.cs)也可以简化代码,只需要确定上下文绑定的视图模型(VM)即可<br> ```csharp public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); DataContext = new MainWindowVMModel(); } } ``` ## 常见 MVVM 框架 > metarial design prism toolkitmvvm
扫一扫手机看
点击排行
windows 文件资源管理器使用
Layui 弹窗open使用说明
SQL Server 中字符串函数使用
C# 使用QQ邮箱代理做邮件接收功能
SQL Server关于apply的两种形式cross apply 和 outer apply
ASP.NET MVC 模型的自定义验证
nvm安装及常用命令
SQL Server 中数据类型转换
SQL Server 中WITH AS短语的使用
IE浏览器下AJAX缓存问题导致数据不更新的解决办法
订阅号