WPF MVVM实例三
在没给大家讲解wpf mwm示例之前先给大家简单说下MVVM理论知识:
WPF技术的主要特点是数据驱动UI,所以在使用WPF技术开发的过程中是以数据为核心的,WPF提供了数据绑定机制,当数据发生变化时,WPF会自动发出通知去更新UI。
我们使用模式,一般是想达到高内聚低耦合。在WPF开发中,经典的编程模式是MVVM,是为WPF量身定做的模式,该模式充分利用了WPF的数据绑定机制,最大限度地降低了Xmal文件和CS文件的耦合度,也就是UI显示和逻辑代码的耦合度,如需要更换界面时,逻辑代码修改很少,甚至不用修改。与WinForm开发相比,我们一般在后置代码中会使用控件的名字来操作控件的属性来更新UI,而在WPF中通常是通过数据绑定来更新UI;在响应用户操作上,WinForm是通过控件的事件来处理,而WPF可以使用命令绑定的方式来处理,耦合度将降低。
首先MVVM设计模式的结构
Views: 由Window/Page/UserControl等构成,通过DataBinding与ViewModels建立关联;
ViewModels:由一组命令,可以绑定的属性,操作逻辑构成;因为View与ViewModel进行了解耦,我们可以对ViewModel进行Unit Test;
Models:可以是实体对象或者Web服务;
下面通过一个简单的例子,来介绍一些WPF MVVM模式。首先项目结构:
DelegateCommand.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 | using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using WpfApp13.Commands; namespace WpfApp13.ViewModels { class MainWindowViewModel:NotificationObject { private double input1; public double Input1 { get { return input1; } set { input1 = value; this .RaisePropertyChange( "Input1" ); } } private double input2; public double Input2 { get { return input2; } set { input2 = value; this .RaisePropertyChange( "Input2" ); } } private double result; public double Result { get { return result; } set { result = value; this .RaisePropertyChange( "Result" ); } } public DelegateCommand AddCommand { get ; set ; } public void Add( object parameter) { this .Result = this .Input1 + this .Input2; } public MainWindowViewModel() { this .AddCommand = new DelegateCommand(); this .AddCommand.ExcuteAction = new Action< object >( this .Add); } } } |
MainWindowViewModel.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 | using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using WpfApp13.Commands; namespace WpfApp13.ViewModels { class MainWindowViewModel:NotificationObject { private double input1; public double Input1 { get { return input1; } set { input1 = value; this .RaisePropertyChange( "Input1" ); } } private double input2; public double Input2 { get { return input2; } set { input2 = value; this .RaisePropertyChange( "Input2" ); } } private double result; public double Result { get { return result; } set { result = value; this .RaisePropertyChange( "Result" ); } } public DelegateCommand AddCommand { get ; set ; } public void Add( object parameter) { this .Result = this .Input1 + this .Input2; } public MainWindowViewModel() { this .AddCommand = new DelegateCommand(); this .AddCommand.ExcuteAction = new Action< object >( this .Add); } } } |
NotificationObject.CS
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | using System; using System.Collections.Generic; using System.ComponentModel; using System.Linq; using System.Text; using System.Threading.Tasks; namespace WpfApp13.ViewModels { class NotificationObject : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; public void RaisePropertyChange( string propertyName) { if ( this .PropertyChanged!= null ) { this .PropertyChanged.Invoke( this , new PropertyChangedEventArgs(propertyName)); } } } } |
MainWindow.xaml.CS
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Navigation; using System.Windows.Shapes; using WpfApp13.ViewModels; namespace WpfApp13 { /// <summary> /// MainWindow.xaml 的交互逻辑 /// </summary> public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); this .DataContext = new MainWindowViewModel(); } } } MainWindow.xaml |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | <Window x:Class= "WpfApp13.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:WpfApp13" mc:Ignorable= "d" Title= "MainWindow" Height= "450" Width= "800" > <Grid> <StackPanel> <Slider Name= "slider1" MinHeight= "25" Value= "{Binding Input1}" /> <Slider Name= "slider2" MinHeight= "25" Value= "{Binding Input2}" /> <Slider Name= "slider3" MinHeight= "25" Value= "{Binding Result}" /> <Button Name= "addButton" Content= "ADD" FontSize= "30" MinHeight= "40" Command= "{Binding AddCommand}" /> </StackPanel> </Grid> </Window> |
运行效果:
分别拖动滑块slider1和slider2,点击按钮后slider3就会自动变化
百度网盘源码下载地址:
链接:https://pan.baidu.com/s/1AvBncokY8SiW0fd9XqrPRw
提取码:ttpo
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· C#/.NET/.NET Core技术前沿周刊 | 第 29 期(2025年3.1-3.9)
· 从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异