网站维护进不去怎么办,敬请期待下一句怎么对,小企业网站建设有什么用,wordpress关键词插件近些年来#xff0c;随着WPF在生产#xff0c;制造#xff0c;工业控制等领域应用越来越广发#xff0c;很多企业对WPF开发的需求也逐渐增多#xff0c;使得很多人看到潜在机会#xff0c;不断从Web#xff0c;WinForm开发转向了WPF开发#xff0c;但是WPF开发也有很多…近些年来随着WPF在生产制造工业控制等领域应用越来越广发很多企业对WPF开发的需求也逐渐增多使得很多人看到潜在机会不断从WebWinForm开发转向了WPF开发但是WPF开发也有很多新的概念及设计思想如数据驱动数据绑定依赖属性命令控件模板数据模板MVVM等与传统WinFormASP.NET WebForm开发有很大的差异今天就以一个简单的小例子简述WPF开发中MVVM设计思想及应用。 为什么要用MVVM? 传统的WinForm开发一般采用事件驱动即用户点击事件触发对应的事件并在事件中通过唯一标识符获取页面上用户输入的数据然后进行业务逻辑处理。这样做会有一个弊端就是用户输入(User Interface)和业务逻辑(Business)是紧密耦合在一起的无法做到分离随着项目的业务不断复杂化这种高度耦合的弊端将会越来越明显。并且会出现分工不明确(如后端工程师前端UI)工作无法拆分的现象。所以分层(如MVCMVVM)可测试(Unit Test)前后端分离就成为必须要面对的问题。而今天要讲解的MVVM设计模式就非常好的解决了我们所面临的问题。 什么是MVVM? MVVM即模型(Model)-视图(View)-视图模型(ViewModel) 是用于解耦 UI 代码和非 UI 代码的 设计模式。 借助 MVVM可以在 XAML 中以声明方式定义 UI将 UI使用数据绑定标到包含数据和命令的其他层。 数据绑定提供数据和结构的松散耦合使 UI 和链接的数据保持同步同时可以将用户输入路由到相应的命令。具体如下图所示 如上图所示
View(用户页面)主要用于向使用者展示信息并接收用户输入的信息数据绑定及响应用户的操作Command。ViewModel(用户视图业务逻辑)主要处理客户请求以及数据呈现。Model数据模型作为存储数据的载体是一个个的具体的模型类通过ViewModel进行调用。但是在小型项目中Model并不是必须的。IService(数据接口)数据访问服务用于获取各种类型数据的服务。数据的形式有很多种如网络数据本地数据数据库数据但是在ViewModel调用时都统一封装成了Service。在小型项目中IService数据接口也并不是必须的不属于MVVM的范畴。在上图中DataBase,NetworkLocal等表示不同的数据源形式并不属于MVVM的范畴。 前提条件 要实现MVVM首先需要满足两个条件
属性变更通知在MVVM思想中由WinForm的事件驱动转变成了数据驱动。在C#中普通的属性并不具备变更通知功能要实现变更通知功能必须要实现INotifyPropertyChanged接口。绑定命令在WPF中为了解决事件响应功能之间的耦合提出了绑定命令思想即命令可以绑定的方式与控件建立联系。绑定命令必须实现ICommand接口。
在上述两个条件都满足后如何将ViewModel中的具备变更通知的属性和命令与View中的控件关联起来呢答案就是绑定(Binding)。 当View层的数据控件和具备通知功能的属性进行Binding后Binging就会自动侦听来自接口的PropertyChanged事件。进而达到数据驱动UI的效果可谓【一桥飞架南北天堑变通途】。 MVVM实例 为了进一步感受MVVM的设计思想验证上述的理论知识以实例进行说明。本实例的项目架构如下所示 MVVM核心代码 1. 具备通知功能的属性 首先定义一个抽象类ObservableObject此接口实现INotifyPropertyChanged接口如下所示
using System.ComponentModel;
using System.Runtime.CompilerServices;namespace DemoMVVM.Core
{/// summary/// 可被观测的类/// /summarypublic abstract class ObservableObject : INotifyPropertyChanged{/// summary/// 属性改变事件/// /summarypublic event PropertyChangedEventHandler? PropertyChanged;/// summary/// 属性改变触发方法/// /summary/// param namepropertyName属性名称/paramprotected void RaisePropertyChanged([CallerMemberName]string propertyNamenull){PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));}/// summary/// 设置属性值如果发生改变则调用通知方法/// /summary/// typeparam nameT/typeparam/// param nametarget/param/// param namevalue/param/// param namepropertyName/param/// returns/returnsprotected bool SetPropertyT(ref T target,T value, [CallerMemberName] string propertyName null){if (EqualityComparerT.Default.Equals(target, value)){return false;}else{targetvalue;RaisePropertyChanged(propertyName);return true;}}}
} 注意上述SetProperty主要用于将普通属性变为具备通知功能的属性。 然后定义一个ViewMode基类继承自ObservableObject以备后续扩展如下所示
namespace DemoMVVM.Core
{/// summary/// ViewModel基类继承自ObservableObject/// /summarypublic abstract class ViewModelBase:ObservableObject{}
} 2. 具备绑定功能的命令 首先定义一个DelegateCommand实现ICommand接口如下所示
namespace DemoMVVM.Core
{public class DelegateCommand : ICommand{private Actionobject execute;private Predicateobject canExecute;public event EventHandler? CanExecuteChanged;public DelegateCommand(Actionobject execute, Predicateobject canExecute){if (execute null){throw new ArgumentNullException(execute 不能为空);}this.execute execute;this.canExecute canExecute;}public DelegateCommand(Actionobject execute):this(execute,null){}public bool CanExecute(object? parameter){return canExecute?.Invoke(parameter)!false;}public void Execute(object? parameter){execute?.Invoke(parameter);}}
} 注意DelegateCommand的构造函数接收两个参数一个是Execute(干活的)一个是CanExecute(判断是否可以干活的)。 MVVM应用代码 本实例主要实现两个数的运算。如加减乘除等功能。
首先定义ViewModel继承自ViewModelBase主要实现具备通知功能的属性和命令如下所示
using DemoMVVM.Core;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime;
using System.Text;
using System.Threading.Tasks;namespace DemoMVVM
{public class MainWindowViewModel:ViewModelBase{#region 属性及构造函数private double leftNumber;public double LeftNumber{get { return leftNumber; }set { SetProperty(ref leftNumber , value); }}private double rightNumber;public double RightNumber{get { return rightNumber; }set { SetProperty(ref rightNumber , value); }}private double resultNumber;public double ResultNumber{get { return resultNumber; }set { SetProperty(ref resultNumber , value); }}public MainWindowViewModel(){}#endregion#region 命令private DelegateCommand operationCommand;public DelegateCommand OperationCommand{get {if (operationCommand null){operationCommand new DelegateCommand(Operate);}return operationCommand; }}private void Operate(object obj){if(obj null){return;}var typeobj.ToString();switch (type){case :this.ResultNumber this.LeftNumber this.RightNumber;break;case -:this.ResultNumber this.LeftNumber - this.RightNumber;break;case *:this.ResultNumber this.LeftNumber * this.RightNumber;break;case /:if (this.RightNumber 0){this.ResultNumber 0;}else{this.ResultNumber this.LeftNumber / this.RightNumber;}break;}}#endregion}
} 创建视图并在视图中进行数据绑定将ViewModel和UI关联起来如下所示
Window x:ClassDemoMVVM.MainWindowxmlnshttp://schemas.microsoft.com/winfx/2006/xaml/presentationxmlns:xhttp://schemas.microsoft.com/winfx/2006/xamlxmlns:dhttp://schemas.microsoft.com/expression/blend/2008xmlns:mchttp://schemas.openxmlformats.org/markup-compatibility/2006xmlns:localclr-namespace:DemoMVVMmc:IgnorabledTitleMVVM示例 Height350 Width600GridGrid.ColumnDefinitionsColumnDefinition/ColumnDefinitionColumnDefinition/ColumnDefinitionColumnDefinition Width0.3*/ColumnDefinitionColumnDefinition/ColumnDefinition/Grid.ColumnDefinitionsGrid.RowDefinitionsRowDefinition/RowDefinitionRowDefinition/RowDefinitionRowDefinition/RowDefinitionRowDefinition/RowDefinition/Grid.RowDefinitionsStackPanel Grid.Row1 Grid.Column0 OrientationHorizontalTextBlock TextA1: VerticalAlignmentCenter /TextBlockTextBox Margin10 Width120 Height35 Text{Binding LeftNumber, UpdateSourceTriggerPropertyChanged} VerticalContentAlignmentCenter/TextBox/StackPanelStackPanel Grid.Row1 Grid.Column1 OrientationHorizontalTextBlock TextA2: VerticalAlignmentCenter /TextBlockTextBox Margin10 Width120 Height35 Text{Binding RightNumber, UpdateSourceTriggerPropertyChanged} VerticalContentAlignmentCenter/TextBox/StackPanelTextBlock Grid.Row1 Grid.Column2 Text VerticalAlignmentCenter HorizontalAlignmentCenter/TextBlockStackPanel Grid.Row1 Grid.Column3 OrientationHorizontalTextBlock TextA3: VerticalAlignmentCenter /TextBlockTextBox Margin10 Width120 Height35 Text{Binding ResultNumber, UpdateSourceTriggerPropertyChanged} VerticalContentAlignmentCenter/TextBox/StackPanelStackPanel Grid.Row2 Grid.ColumnSpan4 OrientationHorizontal HorizontalAlignmentCenterButton Content Width100 Height35 Margin10 Command{Binding OperationCommand} CommandParameter/ButtonButton Content- Width100 Height35 Margin10 Command{Binding OperationCommand} CommandParameter-/ButtonButton Content* Width100 Height35 Margin10 Command{Binding OperationCommand} CommandParameter*/ButtonButton Content/ Width100 Height35 Margin10 Command{Binding OperationCommand} CommandParameter//Button/StackPanel /Grid
/Window 注意在xaml前端UI代码中分别对TextBox的Text和Button的Command进行了绑定已达到数据驱动UI以及UI响应客户的功能。
在UI的构造函数中将DataContext数据上下文和ViewModel进行关联如下所示
namespace DemoMVVM
{/// summary/// Interaction logic for MainWindow.xaml/// /summarypublic partial class MainWindow : Window{private MainWindowViewModel viewModel;public MainWindow(){InitializeComponent();viewModel new MainWindowViewModel();this.DataContext viewModel;}}
} MVVM实例演示 通过以上步骤已经完成了MVVM的简单应用。实例演示如下 以上就是深入理解WPF中MVVM的设计思想的全部内容。希望可以抛砖引玉一起学习共同进步。