深入理解WPF中MVVM的设计思想

这篇具有很好参考价值的文章主要介绍了深入理解WPF中MVVM的设计思想。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

近些年来,随着WPF在生产,制造,工业控制等领域应用越来越广发,很多企业对WPF开发的需求也逐渐增多,使得很多人看到潜在机会,不断从Web,WinForm开发转向了WPF开发,但是WPF开发也有很多新的概念及设计思想,如:数据驱动,数据绑定,依赖属性,命令,控件模板,数据模板,MVVM等,与传统WinForm,ASP.NET WebForm开发,有很大的差异,今天就以一个简单的小例子,简述WPF开发中MVVM设计思想及应用。

深入理解WPF中MVVM的设计思想

 

为什么要用MVVM?

 

传统的WinForm开发,一般采用事件驱动,即用户点击事件,触发对应的事件,并在事件中通过唯一标识符获取页面上用户输入的数据,然后进行业务逻辑处理。这样做会有一个弊端,就是用户输入(User Interface)和业务逻辑(Business)是紧密耦合在一起的,无法做到分离,随着项目的业务不断复杂化,这种高度耦合的弊端将会越来越明显。并且会出现分工不明确(如:后端工程师,前端UI),工作无法拆分的现象。所以分层(如:MVC,MVVM),可测试(Unit Test),前后端分离,就成为必须要面对的问题。而今天要讲解的MVVM设计模式,就非常好的解决了我们所面临的问题。

 

什么是MVVM?

 

MVVM即模型(Model)-视图(View)-视图模型(ViewModel) ,是用于解耦 UI 代码和非 UI 代码的 设计模式。 借助 MVVM,可以在 XAML 中以声明方式定义 UI,将 UI使用数据绑定标到包含数据和命令的其他层。 数据绑定提供数据和结构的松散耦合,使 UI 和链接的数据保持同步,同时可以将用户输入路由到相应的命令。具体如下图所示:

深入理解WPF中MVVM的设计思想

如上图所示:

  1. View(用户页面),主要用于向使用者展示信息,并接收用户输入的信息(数据绑定),及响应用户的操作(Command)。
  2. ViewModel(用户视图业务逻辑),主要处理客户请求,以及数据呈现。
  3. Model数据模型,作为存储数据的载体,是一个个的具体的模型类,通过ViewModel进行调用。但是在小型项目中,Model并不是必须的
  4. IService(数据接口),数据访问服务,用于获取各种类型数据的服务。数据的形式有很多种,如网络数据,本地数据,数据库数据,但是在ViewModel调用时,都统一封装成了Service。在小型项目中,IService数据接口也并不是必须的,不属于MVVM的范畴
  5. 在上图中,DataBase,Network,Local等表示不同的数据源形式,并不属于MVVM的范畴。

 

前提条件

 

要实现MVVM,首先需要满足两个条件:

  1. 属性变更通知,在MVVM思想中,由WinForm的事件驱动,转变成了数据驱动。在C#中,普通的属性,并不具备变更通知功能,要实现变更通知功能,必须要实现INotifyPropertyChanged接口。
  2. 绑定命令,在WPF中,为了解决事件响应功能之间的耦合,提出了绑定命令思想,即命令可以绑定的方式与控件建立联系。绑定命令必须实现ICommand接口。

在上述两个条件都满足后,如何将ViewModel中的具备变更通知的属性和命令,与View中的控件关联起来呢?答案就是绑定(Binding)

深入理解WPF中MVVM的设计思想

当View层的数据控件和具备通知功能的属性进行Binding后,Binging就会自动侦听来自接口的PropertyChanged事件。进而达到数据驱动UI的效果,可谓【一桥飞架南北,天堑变通途】。

 

MVVM实例

 

为了进一步感受MVVM的设计思想,验证上述的理论知识,以实例进行说明。本实例的项目架构如下所示:

深入理解WPF中MVVM的设计思想

 

MVVM核心代码

 

1. 具备通知功能的属性

 

首先定义一个抽象类ObservableObject,此接口实现INotifyPropertyChanged接口,如下所示:

using System.ComponentModel;
using System.Runtime.CompilerServices;

namespace DemoMVVM.Core
{
    /// <summary>
    /// 可被观测的类
    /// </summary>
    public abstract class ObservableObject : INotifyPropertyChanged
    {
        /// <summary>
        /// 属性改变事件
        /// </summary>
        public event PropertyChangedEventHandler? PropertyChanged;

        /// <summary>
        /// 属性改变触发方法
        /// </summary>
        /// <param name="propertyName">属性名称</param>
        protected void RaisePropertyChanged([CallerMemberName]string propertyName=null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }

        /// <summary>
        /// 设置属性值,如果发生改变,则调用通知方法
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="target"></param>
        /// <param name="value"></param>
        /// <param name="propertyName"></param>
        /// <returns></returns>
        protected bool SetProperty<T>(ref T target,T value, [CallerMemberName] string propertyName = null)
        {
            if (EqualityComparer<T>.Default.Equals(target, value))
            {
                return false;
            }
            else
            {
                target=value;
                RaisePropertyChanged(propertyName);
                return true;
            }
        }
    }
}

注意:上述SetProperty主要用于将普通属性,变为具备通知功能的属性。

 

然后定义一个ViewMode基类,继承自ObservableObject,以备后续扩展,如下所示:

namespace DemoMVVM.Core
{
    /// <summary>
    /// ViewModel基类,继承自ObservableObject
    /// </summary>
    public abstract class ViewModelBase:ObservableObject
    {

    }
}

 

2. 具备绑定功能的命令

 

首先定义一个DelegateCommand,实现ICommand接口,如下所示:

namespace DemoMVVM.Core
{
    public class DelegateCommand : ICommand
    {
        private Action<object> execute;
        private Predicate<object> canExecute;


        public event EventHandler? CanExecuteChanged;

        public DelegateCommand(Action<object> execute, Predicate<object> canExecute)
        {
            if (execute == null)
            {
                throw new ArgumentNullException("execute 不能为空");
            }
            this.execute = execute;
            this.canExecute = canExecute;
        }

        public DelegateCommand(Action<object> 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 type=obj.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:Class="DemoMVVM.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:DemoMVVM"
        mc:Ignorable="d"
        Title="MVVM示例" Height="350" Width="600">
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition></ColumnDefinition>
            <ColumnDefinition></ColumnDefinition>
            <ColumnDefinition Width="0.3*"></ColumnDefinition>
            <ColumnDefinition></ColumnDefinition>
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition></RowDefinition>
            <RowDefinition></RowDefinition>
            <RowDefinition></RowDefinition>
            <RowDefinition></RowDefinition>
        </Grid.RowDefinitions>
        <StackPanel Grid.Row="1" Grid.Column="0" Orientation="Horizontal">
            <TextBlock Text="A1:" VerticalAlignment="Center" ></TextBlock>
            <TextBox  Margin="10" Width="120" Height="35" Text="{Binding LeftNumber, UpdateSourceTrigger=PropertyChanged}" VerticalContentAlignment="Center"></TextBox>
        </StackPanel>
        <StackPanel Grid.Row="1" Grid.Column="1" Orientation="Horizontal">
            <TextBlock Text="A2:" VerticalAlignment="Center" ></TextBlock>
            <TextBox  Margin="10" Width="120" Height="35" Text="{Binding RightNumber, UpdateSourceTrigger=PropertyChanged}" VerticalContentAlignment="Center"></TextBox>
        </StackPanel>
        <TextBlock Grid.Row="1" Grid.Column="2" Text="=" VerticalAlignment="Center" HorizontalAlignment="Center"></TextBlock>
        <StackPanel Grid.Row="1" Grid.Column="3" Orientation="Horizontal">
            <TextBlock Text="A3:" VerticalAlignment="Center" ></TextBlock>
            <TextBox  Margin="10" Width="120" Height="35" Text="{Binding ResultNumber, UpdateSourceTrigger=PropertyChanged}" VerticalContentAlignment="Center"></TextBox>
        </StackPanel>
        <StackPanel Grid.Row="2" Grid.ColumnSpan="4" Orientation="Horizontal" HorizontalAlignment="Center">
            <Button Content="+" Width="100" Height="35" Margin="10" Command="{Binding OperationCommand}" CommandParameter="+"></Button>
            <Button Content="-" Width="100" Height="35" Margin="10" Command="{Binding OperationCommand}" CommandParameter="-"></Button>
            <Button Content="*" Width="100" Height="35" Margin="10" Command="{Binding OperationCommand}" CommandParameter="*"></Button>
            <Button Content="/" Width="100" Height="35" Margin="10" 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
    /// </summary>
    public partial class MainWindow : Window
    {
        private MainWindowViewModel viewModel;

        public MainWindow()
        {
            InitializeComponent();
            viewModel = new MainWindowViewModel();
            this.DataContext = viewModel;
        }
    }
}

 

MVVM实例演示

 

通过以上步骤,已经完成了MVVM的简单应用。实例演示如下:

深入理解WPF中MVVM的设计思想

以上就是深入理解WPF中MVVM的设计思想的全部内容。希望可以抛砖引玉,一起学习,共同进步。文章来源地址https://www.toymoban.com/news/detail-712206.html

到了这里,关于深入理解WPF中MVVM的设计思想的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【C++ 观察者模式 思想理解】C++中的观察者模式:松耦合设计与动态交互的艺术,合理使用智能指针观察者

    在进入技术细节之前,理解观察者模式(Observer Pattern)的基本概念和它在现代编程中的重要性是至关重要的。 观察者模式是一种设计模式,它定义了对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并自动更新。在C++中,这个

    2024年01月24日
    浏览(44)
  • 设计模式-01.设计思想

    此系列文章非本人原创,是学习笔记。 下面讲一些常见的设计思想 这个原则非常重要,是一种非常有效的提高代码质量的手段,在平时的开发中特别经常被用到。 如何解读原则中的“接口”二字? “基于接口而非实现编程”这条原则的英文描述是:“Program to an interface, n

    2024年02月07日
    浏览(58)
  • 算法设计思想——动态规划

    是一种常见的算法设计方法,用于解决一类重叠子问题的优化问题。他的基本思想是将问题分解成多个重叠的子问题,递归求解,并将子问题的求解缓存起来,避免重复计算,从而得到问题的解。 动态规划通常适用于以下两个条件的问题: 1.重叠子问题:原问题可以分解为若

    2024年02月03日
    浏览(35)
  • Spring核心设计思想

    目录 前言: Spring是什么 什么是IoC 传统开发思想 IoC开发思想 Spring IoC 什么是DI 小结:     官网中提出:Spring makes programming Java quicker, easier, and safer for everybody. Spring’s focus on speed, simplicity, and productivity has made it the world\\\'s most popular Java framework.     Spring 使编程 Java 对每个人来

    2023年04月17日
    浏览(35)
  • Spring 核心与设计思想

    ✏️作者:银河罐头 📋系列专栏:JavaEE 🌲 “种一棵树最好的时间是十年前,其次是现在” 通常所说的 Spring 指的是 Spring Framework(Spring 框架)。 Spring 是包含多种工具方法的 IoC 容器。 IoC(Inversion of Control): 控制反转 \\\"控制反转\\\"又是什么意思? 下面以一个程序来举例。 假如我

    2024年02月02日
    浏览(41)
  • 闪电网络协议设计思想剖析

    闪电网络可能是比特币之上部署的最受期待的技术创新。闪电网络,为由 Joseph Poon 和 Tadge Dryja 于2015年首次提出的支付层,承诺支持: 用户之间几乎无限数量的链下交易, 几乎免费, 同时利用比特币提供的安全性。 2016年时,至少三个公司——Poon 和 Dryja 的 Lightning、 Block

    2024年03月20日
    浏览(51)
  • 【Spring】核心与设计思想

     哈喽,哈喽,大家好~ 我是你们的老朋友: 保护小周ღ   谈起Java 圈子里的框架,最年长最耀眼的莫过于 Spring 框架啦,如今已成为最流行、最广泛使用的Java开发框架之一。不知道大家有没有在使用 Spring 框架的时候思考过这些问题, 什么是框架?Spring 是什么?如何理解

    2024年02月08日
    浏览(29)
  • Spring框架核心与设计思想

    我们一般所说的Spring指的是Spring Framework(Spring 框架),它是一个开源的框架,Spring支持广泛的应用场景,它可以让Java企业级的应用程序开发变得更简单,官方一点的回答:spring是J2EE应用程序框架,是轻量级的IoC和AOP的容器框架,主要是针对javaBean的生命周期进行管理的轻量级

    2023年04月15日
    浏览(33)
  • Spring框架概述及核心设计思想

    我们通常所说的 Spring 指的是 Spring Framework(Spring 框架),它是⼀个开源框架,有着活跃而庞大的社区,这就是它之所以能长久不衰的原因;Spring 支持广泛的应用场景,它可以让 Java 企业级的应用程序开发起来更简单。 用⼀句话概括 Spring: Spring 框架是包含了众多工具方法的

    2024年02月16日
    浏览(27)
  • 从架构设计思想出发看Flutter

    Flutter 是一种流行的移动应用程序开发框架,它的设计特点之一是可以使用单一代码库构建 iOS 和 Android 应用程序。然而,对于功能比较多、模块比较复杂的应用程序,仅凭单一的代码库就可能导致代码的复杂性和维护难度的增加。在这种情况下,通过合适的应用程序架构设计

    2024年02月07日
    浏览(61)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包