当前位置: 首页 > news >正文

用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 项目

  1. 打开 Visual Studio,新建一个 WPF 应用程序项目。
  2. 命名项目,例如 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&#xff08;Model-View-ViewModel&#xff09;是一种架构模式&#xff0c;广泛应用于现代前端开发&#xff0c;尤其是在微软的WPF&#xff08;Windows Presentation Foundation&#xff09;应用程序中。它旨在通过将视图&#xff08;UI&#xff09;与业务逻辑&#xff08;…...

C++中的动态断言和静态断言

C中包含动态断言&#xff08;assert&#xff09;和静态断言&#xff08;static_assert&#xff09;&#xff0c;下面分别分析各自的用法。 1.动态断言&#xff08;assert&#xff09; assert 是一个宏&#xff0c;在预处理阶段不生效&#xff0c;在运行阶段才起作用&#xff0…...

运算放大器的学习(一)输入阻抗

输入阻抗 最近需要对运算放大器进行学习&#xff0c;我们后面逐一对其参数进行了解。 首先了解下输入阻抗。 放大电路技术指标测试示意图&#xff1a; 输入电阻&#xff1a; 从放大电路的输入端看进去的等效电阻称为放大电路的输入电阻&#xff0c;如上图&#xff0c;此处考虑…...

Rust枚举之卧龙凤雏(Rust Option枚举、Rust Result枚举)(Rust Enum、Some(T)、Ok(T)、Err(E))链式操作

文章目录 Rust 枚举之卧龙凤雏枚举的基本概念枚举定义示例 Result 枚举&#xff1a;凤雏Result 枚举的定义Result 的使用场景示例 1&#xff1a;文件读取示例 2&#xff1a;链式操作与错误处理 Option 枚举&#xff1a;卧龙Option 枚举的定义Option 的使用场景示例 1&#xff1…...

TCP/IP协议,TCP和UDP区别

TCP/IP&#xff08;Transmission Control Protocol/Internet Protocol&#xff0c;传输控制协议/互联网协议&#xff09;是一组用于计算机网络中的通信协议&#xff0c;它为数据传输提供了标准框架&#xff0c;广泛用于互联网和局域网中。TCP/IP协议包括多个层次&#xff0c;每…...

【go从零单排】Timer、Epoch 时间函数

&#x1f308;Don’t worry , just coding! 内耗与overthinking只会削弱你的精力&#xff0c;虚度你的光阴&#xff0c;每天迈出一小步&#xff0c;回头时发现已经走了很远。 &#x1f4d7;概念 在 Go 语言中&#xff0c;time.Timer 是一个用于在指定时间后执行操作的计时器。…...

壁仞科技上市前最后一波 校招 社招 内推

随着美国大选结束&#xff0c;国内GPU 产业得到空前的的发展空间&#xff0c;国内芯片相关股票一片飘红。 国内大型 GPU厂商壁仞科技&#xff0c;摩尔线程等正紧锣密鼓地加紧上市。 GPGPU 芯片赛道来到了史无前例的红利点&#xff0c;抓住机会&#x1f4aa; 壁仞科技正在火热…...

【微软报告:多模态基础模型】(2)视觉理解

欢迎关注【youcans的AGI学习笔记】原创作品 【微软报告&#xff1a;多模态基础模型】&#xff08;1&#xff09;从专家到通用助手 【微软报告&#xff1a;多模态基础模型】&#xff08;2&#xff09;视觉理解 【微软报告&#xff1a;多模态基础模型】&#xff08;3&#xff09;…...

Linux 驱动

四十三、Linux设备树 43.1 DTS、DTB 和 DTC DTS 是设备树源码文件 DTB 是将DTS 编译以后得到的二进制文件。 DTC 工具将.dts 编译为.dtb 43.2 DTS语法 43.2.1 .dtsi 头文件 在.dts 设备树文件中&#xff0c;可以通过“#include”来引用.h、.dtsi 和.dts 文件。 …...

【数学二】线性代数-线性方程组-齐次线性方程组、非齐次线性方程组

考试要求 1、会用克拉默法则. 2、理解齐次线性方程组有非零解的充分必要条件及非齐次线性方程组有解的充分必要条件. 3、理解齐次线性方程组的基础解系及通解的概念,掌握齐次线性方程组基础解系和通解的求法. 4、理解非齐次线性方程组的解的结构及通解的概念. 5、会用初等行变…...

Git别名设置

在 Git 中设置命令别名可以让你更高效地使用常见的 Git 命令。通过为常用命令创建简短的别名&#xff0c;可以减少输入的字符数并加速工作流程。 参考链接 设置 Git 命令别名的方法&#xff1a; 使用 Git 配置命令&#xff1a; Git 允许通过 git config 命令来设置命令别名。这…...

算法基础 -- 红黑树原理与插入伪代码

红黑树原理与插入伪代码 红黑树的原理 红黑树是一种自平衡的二叉搜索树&#xff0c;通过对节点的颜色&#xff08;红色或黑色&#xff09;以及结构的约束条件来保持树的平衡。红黑树的原理可以通过以下五个特性描述&#xff1a; 节点是红色或黑色。根节点必须是黑色。所有叶…...

力扣 LeetCode 27. 移除元素(Day1:数组)

解题思路&#xff1a; 注意&#xff1a;数组只能覆盖&#xff0c;不能删除 erase方法的复杂度为O( n )而不是O( 1 )&#xff0c;因为需要把删除后后面的数组向前移动 方法一&#xff1a;双层for循环暴力 方法二&#xff1a;快慢指针 fast表示新数组的元素 slow表示新数组元…...

微服务链路追踪skywalking安装

‌SkyWalking是一个开源的分布式追踪系统&#xff0c;主要用于监控和分析微服务架构下的应用性能。‌ 它提供了分布式追踪、服务网格遥测分析、度量聚合和可视化一体化解决方案&#xff0c;特别适用于微服务、云原生架构和基于容器的环境&#xff08;如Docker、K8s、Mesos&…...

mqtt学习笔记(一)

以解决问题方式逐步学习探索 mqtt使用场景mqtt可能缺点mqtt学习疑问探索1、mqtt主题发布过的历史消息&#xff0c;全新连接的client能消费到吗&#xff1f;2、mqtt的client掉线如何重连&#xff0c;重连后订阅的topic配置还在不&#xff1f;3、mqtt的client掉线重连后&#xff…...

Kafka Eagle 安装教程

目录 前言 一、安装前的准备 1. 系统要求 2. 安装 JDK 3. 安装 Kafka 和 Zookeeper 4. MySQL 环境准备 二、下载并安装 Kafka Eagle 三、配置 Kafka Eagle 1. 编辑配置文件 2. 配置 Kafka 和 Zookeeper 信息 四、启动 Kafka Eagle 五、访问 Kafka Eagle 六、测试功…...

Ajax 获取进度和中断请求

HTML加入一些内容方便看效果和做交互&#xff1a; <div><p>当前传输进度&#xff1a;<span id"progress">0%</span></p><button id"send">发送</button><button id"btn">中断</button> …...

实验5:网络设备发现、管理和维护

实验5&#xff1a;网络设备发现、管理和维护 实验目的及要求&#xff1a; 通过实验&#xff0c;掌握Cisco 路由器和交换机的IOS配置管理。自动从NTP服务器获取时间信息。能够利用TFTP服务器实现路由器和交换机配置文件的备份和恢复。同时验证CDP协议和LLDP协议的网络参数。完…...

kafka 生产经验——数据积压(消费者如何提高吞吐量)

bit --> byte --> kb -->mb -->gb --> tb --> pb --> eb -> zb -->yb...

对等同步身份认证(Simultaneous Authentication of Equals,简称SAE)介绍

对等同步身份认证&#xff08;Simultaneous Authentication of Equals&#xff0c;简称SAE&#xff09;介绍 对等同步身份认证&#xff08;Simultaneous Authentication of Equals&#xff0c;简称SAE&#xff09;是一种基于密码的身份验证方法&#xff0c;用于安全地交换密钥…...

RestClient

什么是RestClient RestClient 是 Elasticsearch 官方提供的 Java 低级 REST 客户端&#xff0c;它允许HTTP与Elasticsearch 集群通信&#xff0c;而无需处理 JSON 序列化/反序列化等底层细节。它是 Elasticsearch Java API 客户端的基础。 RestClient 主要特点 轻量级&#xff…...

国防科技大学计算机基础课程笔记02信息编码

1.机内码和国标码 国标码就是我们非常熟悉的这个GB2312,但是因为都是16进制&#xff0c;因此这个了16进制的数据既可以翻译成为这个机器码&#xff0c;也可以翻译成为这个国标码&#xff0c;所以这个时候很容易会出现这个歧义的情况&#xff1b; 因此&#xff0c;我们的这个国…...

脑机新手指南(八):OpenBCI_GUI:从环境搭建到数据可视化(下)

一、数据处理与分析实战 &#xff08;一&#xff09;实时滤波与参数调整 基础滤波操作 60Hz 工频滤波&#xff1a;勾选界面右侧 “60Hz” 复选框&#xff0c;可有效抑制电网干扰&#xff08;适用于北美地区&#xff0c;欧洲用户可调整为 50Hz&#xff09;。 平滑处理&…...

椭圆曲线密码学(ECC)

一、ECC算法概述 椭圆曲线密码学&#xff08;Elliptic Curve Cryptography&#xff09;是基于椭圆曲线数学理论的公钥密码系统&#xff0c;由Neal Koblitz和Victor Miller在1985年独立提出。相比RSA&#xff0c;ECC在相同安全强度下密钥更短&#xff08;256位ECC ≈ 3072位RSA…...

Xshell远程连接Kali(默认 | 私钥)Note版

前言:xshell远程连接&#xff0c;私钥连接和常规默认连接 任务一 开启ssh服务 service ssh status //查看ssh服务状态 service ssh start //开启ssh服务 update-rc.d ssh enable //开启自启动ssh服务 任务二 修改配置文件 vi /etc/ssh/ssh_config //第一…...

Python如何给视频添加音频和字幕

在Python中&#xff0c;给视频添加音频和字幕可以使用电影文件处理库MoviePy和字幕处理库Subtitles。下面将详细介绍如何使用这些库来实现视频的音频和字幕添加&#xff0c;包括必要的代码示例和详细解释。 环境准备 在开始之前&#xff0c;需要安装以下Python库&#xff1a;…...

JDK 17 新特性

#JDK 17 新特性 /**************** 文本块 *****************/ python/scala中早就支持&#xff0c;不稀奇 String json “”" { “name”: “Java”, “version”: 17 } “”"; /**************** Switch 语句 -> 表达式 *****************/ 挺好的&#xff…...

QT: `long long` 类型转换为 `QString` 2025.6.5

在 Qt 中&#xff0c;将 long long 类型转换为 QString 可以通过以下两种常用方法实现&#xff1a; 方法 1&#xff1a;使用 QString::number() 直接调用 QString 的静态方法 number()&#xff0c;将数值转换为字符串&#xff1a; long long value 1234567890123456789LL; …...

【JavaWeb】Docker项目部署

引言 之前学习了Linux操作系统的常见命令&#xff0c;在Linux上安装软件&#xff0c;以及如何在Linux上部署一个单体项目&#xff0c;大多数同学都会有相同的感受&#xff0c;那就是麻烦。 核心体现在三点&#xff1a; 命令太多了&#xff0c;记不住 软件安装包名字复杂&…...

Android 之 kotlin 语言学习笔记三(Kotlin-Java 互操作)

参考官方文档&#xff1a;https://developer.android.google.cn/kotlin/interop?hlzh-cn 一、Java&#xff08;供 Kotlin 使用&#xff09; 1、不得使用硬关键字 不要使用 Kotlin 的任何硬关键字作为方法的名称 或字段。允许使用 Kotlin 的软关键字、修饰符关键字和特殊标识…...