用MVVM设计模式提升WPF开发体验:分层架构与绑定实例解析
MVVM(Model-View-ViewModel)是一种架构模式,广泛应用于现代前端开发,尤其是在微软的WPF(Windows Presentation Foundation)应用程序中。它旨在通过将视图(UI)与业务逻辑(模型)分离,达到更高的代码可维护性和可测试性。MVVM 在 Microsoft 的推行下,成为 WPF 应用开发的标准设计模式之一。
一、历史背景
在 GUI 应用开发中,代码的复杂性主要来源于 UI 和业务逻辑的耦合。传统的MVC(Model-View-Controller)架构尝试解决这一问题,通过分离模型和视图,开发者可以更轻松地管理代码。MVVM 是对MVC 的改进,提出了视图模型(ViewModel)的概念,将视图与模型连接起来,极大地提升了数据绑定和双向数据更新的便捷性和灵活性。
MVVM 模式主要借助于 WPF 的数据绑定、命令和属性更改通知来实现,使得开发者可以将数据流的处理逻辑放入 ViewModel中,做到视图和数据逻辑的完全分离。
二、MVVM 模式的组成
Model:代表数据结构和业务逻辑,包含数据实体、数据访问层和业务规则的实现。它与视图无关,专注于应用程序的核心数据。
View:表示用户界面,是应用程序的可视化部分。它通过绑定从
ViewModel 获取数据,不直接处理数据逻辑。
ViewModel:充当 View 与 Model 的桥梁,包含 UI 逻辑和 Model 数据的映射逻辑。ViewModel 通过属性绑定和命令,向视图提供数据,并响应用户操作。
三、WPF 和 MVVM 的结合
WPF 为 MVVM 提供了强大的支持,其中数据绑定和命令是关键功能。WPF 的数据绑定可以通过简单的绑定语法,将 ViewModel 的数据呈现到视图中,而 WPF 的命令机制可以将用户的操作与 ViewModel 中的方法关联起来。
1. 数据绑定
数据绑定是 WPF 中的重要功能,它使得 ViewModel 的属性可以直接绑定到视图中的控件上。例如,通过绑定一个属性,TextBox 控件的内容可以实时更新到 ViewModel 的数据。
2. 命令
WPF 命令提供了一种方法,可以将按钮等控件的交互行为与 ViewModel 中的操作逻辑连接起来。通过 ICommand 接口,命令可以定义在 ViewModel 中并直接绑定到视图控件。
四、MVVM 应用实例:创建一个简单的 WPF 应用程序
以下将从零开始创建一个简单的 MVVM 应用,展示基本的 MVVM 模式实现。
4.1第一步:创建 WPF 项目
- 打开 Visual Studio,新建一个 WPF 应用程序项目。
- 命名项目,例如 MVVMExample。
项目创建成功后,会生成 MainWindow.xaml,我们将这个文件作为 View 视图部分。
4.2 第二步:创建 Model
在项目中添加一个 Models 文件夹,并创建一个数据类 Person.cs:
// Models/Person.cs
// 创建 Modelpublic class Person{public string FirstName { get; set; }public string LastName { get; set; }}
此 Person 类表示应用程序的数据结构。
4.3 第三步:创建 ViewModel
在项目中添加一个 ViewModels 文件夹,并创建 MainViewModel.cs,负责处理 Person 数据并提供给视图。
// ViewModels/MainViewModel.cs
using System.ComponentModel;
using MVVMExample.Models;namespace MVVMExample.ViewModels
{// 定义 ViewModel,充当视图和数据模型之间的中介。public class MainViewModel : INotifyPropertyChanged // 数据绑定中常用的接口,它允许对象通知其属性发生了变化。{// 定义字段 _personprivate Person _person;public Person Person{get => _person;set{_person = value;OnPropertyChanged(nameof(Person));}}// 实现构造方法public MainViewModel(){Person = new Person(){FirstName = "John",LastName = "Doe"};}public event PropertyChangedEventHandler? PropertyChanged;protected void OnPropertyChanged(string propertyName){//调用 PropertyChanged 事件的订阅者(通常是 UI 控件)进行更新。当 PropertyChanged 事件被触发时,//它会传递一个 PropertyChangedEventArgs 对象,该对象包含属性名 propertyName。?. 是空值检查操作符,确保在没有订阅者的情况下不会抛出异常。PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));}}
}
该 ViewModel 实现了 INotifyPropertyChanged 接口,允许通知视图属性更改。MainViewModel 类在初始化时创建了一个 Person 对象。
4.4 第四步:创建 View
回到 MainWindow.xaml,我们将添加 XAML 代码来展示 Person 的信息。
<!-- MainWindow.xaml -->
<Window x:Class="WpfApp1.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:WpfApp1"mc:Ignorable="d"Title="MainWindow" Height="450" Width="800"><!--创建View--><!--通过设置 DataContext,我们可以将视图模型(MainViewModel)绑定到当前窗口。所有在视图中使用数据绑定的元素都会通过这个数据上下文来获取数据。--><Window.DataContext><!--创建一个 MainViewModel 的实例,并将它作为数据上下文绑定到窗口。这意味着窗口中的所有数据绑定都会访问 MainViewModel 中的属性和数据。--><local:MainViewModel /></Window.DataContext><StackPanel><!--通过绑定,TextBox 的文本将与 MainViewModel 中的 Person.FirstName 属性保持同步。--><!--UpdateSourceTrigger=PropertyChanged这个属性告诉 WPF,当用户在文本框中修改文本时,立即将修改的值更新到 Person.FirstName 属性。这意味着属性会实时更新,而不仅仅是当控件失去焦点时才更新。--><TextBox Text="{Binding Person.FirstName,UpdateSourceTrigger=PropertyChanged}" Margin="10" /><TextBox Text="{Binding Person.LastName,UpdateSourceTrigger=PropertyChanged}" Margin="10" /><TextBlock Text="{Binding Person.FirstName}" Margin="10" FontSize="16" /><TextBlock Text="{Binding Person.LastName}" Margin="10" FontSize="16" /></StackPanel>
</Window>
此 XAML 文件展示了一个简单的 UI,包含两个 TextBox 和两个 TextBlock。TextBox 控件绑定到 Person.FirstName 和 Person.LastName 属性,允许用户输入姓名和姓氏。绑定的 UpdateSourceTrigger=PropertyChanged 确保属性值在更改时立即更新。
4.5 第五步:测试应用程序
启动应用程序,您会看到两个可编辑的文本框和两个文本块。编辑 TextBox 内容时,TextBlock 内容会即时更新,验证了数据绑定和 ViewModel 的有效性。

五、总结
使用 MVVM 模式可以清晰地分离视图和数据逻辑,特别是在大型应用程序中更为显著。在 MVVM 中:
View 负责 UI,展示数据;
ViewModel 负责处理 UI 与数据之间的绑定,管理业务逻辑;
Model 负责数据层,保持核心数据和规则。
通过这种结构化的方式,WPF 中的开发者可以构建更高效的、易维护的应用。
相关文章:
用MVVM设计模式提升WPF开发体验:分层架构与绑定实例解析
MVVM(Model-View-ViewModel)是一种架构模式,广泛应用于现代前端开发,尤其是在微软的WPF(Windows Presentation Foundation)应用程序中。它旨在通过将视图(UI)与业务逻辑(…...
C++中的动态断言和静态断言
C中包含动态断言(assert)和静态断言(static_assert),下面分别分析各自的用法。 1.动态断言(assert) assert 是一个宏,在预处理阶段不生效,在运行阶段才起作用࿰…...
运算放大器的学习(一)输入阻抗
输入阻抗 最近需要对运算放大器进行学习,我们后面逐一对其参数进行了解。 首先了解下输入阻抗。 放大电路技术指标测试示意图: 输入电阻: 从放大电路的输入端看进去的等效电阻称为放大电路的输入电阻,如上图,此处考虑…...
Rust枚举之卧龙凤雏(Rust Option枚举、Rust Result枚举)(Rust Enum、Some(T)、Ok(T)、Err(E))链式操作
文章目录 Rust 枚举之卧龙凤雏枚举的基本概念枚举定义示例 Result 枚举:凤雏Result 枚举的定义Result 的使用场景示例 1:文件读取示例 2:链式操作与错误处理 Option 枚举:卧龙Option 枚举的定义Option 的使用场景示例 1࿱…...
TCP/IP协议,TCP和UDP区别
TCP/IP(Transmission Control Protocol/Internet Protocol,传输控制协议/互联网协议)是一组用于计算机网络中的通信协议,它为数据传输提供了标准框架,广泛用于互联网和局域网中。TCP/IP协议包括多个层次,每…...
【go从零单排】Timer、Epoch 时间函数
🌈Don’t worry , just coding! 内耗与overthinking只会削弱你的精力,虚度你的光阴,每天迈出一小步,回头时发现已经走了很远。 📗概念 在 Go 语言中,time.Timer 是一个用于在指定时间后执行操作的计时器。…...
壁仞科技上市前最后一波 校招 社招 内推
随着美国大选结束,国内GPU 产业得到空前的的发展空间,国内芯片相关股票一片飘红。 国内大型 GPU厂商壁仞科技,摩尔线程等正紧锣密鼓地加紧上市。 GPGPU 芯片赛道来到了史无前例的红利点,抓住机会💪 壁仞科技正在火热…...
【微软报告:多模态基础模型】(2)视觉理解
欢迎关注【youcans的AGI学习笔记】原创作品 【微软报告:多模态基础模型】(1)从专家到通用助手 【微软报告:多模态基础模型】(2)视觉理解 【微软报告:多模态基础模型】(3)…...
Linux 驱动
四十三、Linux设备树 43.1 DTS、DTB 和 DTC DTS 是设备树源码文件 DTB 是将DTS 编译以后得到的二进制文件。 DTC 工具将.dts 编译为.dtb 43.2 DTS语法 43.2.1 .dtsi 头文件 在.dts 设备树文件中,可以通过“#include”来引用.h、.dtsi 和.dts 文件。 …...
【数学二】线性代数-线性方程组-齐次线性方程组、非齐次线性方程组
考试要求 1、会用克拉默法则. 2、理解齐次线性方程组有非零解的充分必要条件及非齐次线性方程组有解的充分必要条件. 3、理解齐次线性方程组的基础解系及通解的概念,掌握齐次线性方程组基础解系和通解的求法. 4、理解非齐次线性方程组的解的结构及通解的概念. 5、会用初等行变…...
Git别名设置
在 Git 中设置命令别名可以让你更高效地使用常见的 Git 命令。通过为常用命令创建简短的别名,可以减少输入的字符数并加速工作流程。 参考链接 设置 Git 命令别名的方法: 使用 Git 配置命令: Git 允许通过 git config 命令来设置命令别名。这…...
算法基础 -- 红黑树原理与插入伪代码
红黑树原理与插入伪代码 红黑树的原理 红黑树是一种自平衡的二叉搜索树,通过对节点的颜色(红色或黑色)以及结构的约束条件来保持树的平衡。红黑树的原理可以通过以下五个特性描述: 节点是红色或黑色。根节点必须是黑色。所有叶…...
力扣 LeetCode 27. 移除元素(Day1:数组)
解题思路: 注意:数组只能覆盖,不能删除 erase方法的复杂度为O( n )而不是O( 1 ),因为需要把删除后后面的数组向前移动 方法一:双层for循环暴力 方法二:快慢指针 fast表示新数组的元素 slow表示新数组元…...
微服务链路追踪skywalking安装
SkyWalking是一个开源的分布式追踪系统,主要用于监控和分析微服务架构下的应用性能。 它提供了分布式追踪、服务网格遥测分析、度量聚合和可视化一体化解决方案,特别适用于微服务、云原生架构和基于容器的环境(如Docker、K8s、Mesos&…...
mqtt学习笔记(一)
以解决问题方式逐步学习探索 mqtt使用场景mqtt可能缺点mqtt学习疑问探索1、mqtt主题发布过的历史消息,全新连接的client能消费到吗?2、mqtt的client掉线如何重连,重连后订阅的topic配置还在不?3、mqtt的client掉线重连后ÿ…...
Kafka Eagle 安装教程
目录 前言 一、安装前的准备 1. 系统要求 2. 安装 JDK 3. 安装 Kafka 和 Zookeeper 4. MySQL 环境准备 二、下载并安装 Kafka Eagle 三、配置 Kafka Eagle 1. 编辑配置文件 2. 配置 Kafka 和 Zookeeper 信息 四、启动 Kafka Eagle 五、访问 Kafka Eagle 六、测试功…...
Ajax 获取进度和中断请求
HTML加入一些内容方便看效果和做交互: <div><p>当前传输进度:<span id"progress">0%</span></p><button id"send">发送</button><button id"btn">中断</button> …...
实验5:网络设备发现、管理和维护
实验5:网络设备发现、管理和维护 实验目的及要求: 通过实验,掌握Cisco 路由器和交换机的IOS配置管理。自动从NTP服务器获取时间信息。能够利用TFTP服务器实现路由器和交换机配置文件的备份和恢复。同时验证CDP协议和LLDP协议的网络参数。完…...
kafka 生产经验——数据积压(消费者如何提高吞吐量)
bit --> byte --> kb -->mb -->gb --> tb --> pb --> eb -> zb -->yb...
对等同步身份认证(Simultaneous Authentication of Equals,简称SAE)介绍
对等同步身份认证(Simultaneous Authentication of Equals,简称SAE)介绍 对等同步身份认证(Simultaneous Authentication of Equals,简称SAE)是一种基于密码的身份验证方法,用于安全地交换密钥…...
逻辑回归:给不确定性划界的分类大师
想象你是一名医生。面对患者的检查报告(肿瘤大小、血液指标),你需要做出一个**决定性判断**:恶性还是良性?这种“非黑即白”的抉择,正是**逻辑回归(Logistic Regression)** 的战场&a…...
java 实现excel文件转pdf | 无水印 | 无限制
文章目录 目录 文章目录 前言 1.项目远程仓库配置 2.pom文件引入相关依赖 3.代码破解 二、Excel转PDF 1.代码实现 2.Aspose.License.xml 授权文件 总结 前言 java处理excel转pdf一直没找到什么好用的免费jar包工具,自己手写的难度,恐怕高级程序员花费一年的事件,也…...
使用分级同态加密防御梯度泄漏
抽象 联邦学习 (FL) 支持跨分布式客户端进行协作模型训练,而无需共享原始数据,这使其成为在互联和自动驾驶汽车 (CAV) 等领域保护隐私的机器学习的一种很有前途的方法。然而,最近的研究表明&…...
[ICLR 2022]How Much Can CLIP Benefit Vision-and-Language Tasks?
论文网址:pdf 英文是纯手打的!论文原文的summarizing and paraphrasing。可能会出现难以避免的拼写错误和语法错误,若有发现欢迎评论指正!文章偏向于笔记,谨慎食用 目录 1. 心得 2. 论文逐段精读 2.1. Abstract 2…...
现代密码学 | 椭圆曲线密码学—附py代码
Elliptic Curve Cryptography 椭圆曲线密码学(ECC)是一种基于有限域上椭圆曲线数学特性的公钥加密技术。其核心原理涉及椭圆曲线的代数性质、离散对数问题以及有限域上的运算。 椭圆曲线密码学是多种数字签名算法的基础,例如椭圆曲线数字签…...
(转)什么是DockerCompose?它有什么作用?
一、什么是DockerCompose? DockerCompose可以基于Compose文件帮我们快速的部署分布式应用,而无需手动一个个创建和运行容器。 Compose文件是一个文本文件,通过指令定义集群中的每个容器如何运行。 DockerCompose就是把DockerFile转换成指令去运行。 …...
selenium学习实战【Python爬虫】
selenium学习实战【Python爬虫】 文章目录 selenium学习实战【Python爬虫】一、声明二、学习目标三、安装依赖3.1 安装selenium库3.2 安装浏览器驱动3.2.1 查看Edge版本3.2.2 驱动安装 四、代码讲解4.1 配置浏览器4.2 加载更多4.3 寻找内容4.4 完整代码 五、报告文件爬取5.1 提…...
MySQL用户和授权
开放MySQL白名单 可以通过iptables-save命令确认对应客户端ip是否可以访问MySQL服务: test: # iptables-save | grep 3306 -A mp_srv_whitelist -s 172.16.14.102/32 -p tcp -m tcp --dport 3306 -j ACCEPT -A mp_srv_whitelist -s 172.16.4.16/32 -p tcp -m tcp -…...
Unity | AmplifyShaderEditor插件基础(第七集:平面波动shader)
目录 一、👋🏻前言 二、😈sinx波动的基本原理 三、😈波动起来 1.sinx节点介绍 2.vertexPosition 3.集成Vector3 a.节点Append b.连起来 4.波动起来 a.波动的原理 b.时间节点 c.sinx的处理 四、🌊波动优化…...
OD 算法题 B卷【正整数到Excel编号之间的转换】
文章目录 正整数到Excel编号之间的转换 正整数到Excel编号之间的转换 excel的列编号是这样的:a b c … z aa ab ac… az ba bb bc…yz za zb zc …zz aaa aab aac…; 分别代表以下的编号1 2 3 … 26 27 28 29… 52 53 54 55… 676 677 678 679 … 702 703 704 705;…...
