首页 > 其他分享 >MVVM 设计模式

MVVM 设计模式

时间:2023-05-27 17:24:41浏览次数:53  
标签:MVVM double private MainWindow 设计模式 public

本篇文章学习于: 刘铁猛老师《深入浅出WPF》

什么是MVVM模式?

MVVM的全称是——Model、View、ViewModel,翻译过来就是:模型、视图、视图模型。
ViewModel是比较抽象的,它起到承上启下的作用,用于处理业务逻辑。
每一个View都需要有对应的Model和ViewModel。
ViewModel与View的沟通:A.传递数据——数据属性 B.传递操作——命令属性

为什么要使用MVVM模式?

该模式最大的优点就是将UI和业务逻辑进行剥离,使项目高内聚低耦合。美工和后端开发人员可以同时开工,页面修改不会影响到后台的业务逻辑,方便了项目后期的维护。

  • 团队层面:统一思维方式和实现方法
  • 架构层面:稳定,解耦,富有禅意
  • 代码层面:可读,可测,可替换

什么时候用MVVM模式?

如果你只需要显示一句“Hello World”,使用该模式会令你抓狂。如果你是开发一个正儿八经的WPF应用,并且该应用后期会进行功能扩展,维护等操作。那么建议使用MVVM模式开发WPF应用。

MVVM 示例

使用了MVVM模式的程序工作流程图

1. 不使用MVVM实现程序

<Window x:Class="Demo9.WpfMVVM设计模式.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:Demo9.WpfMVVM设计模式"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>
        <Button Content="Save" Click="saveButton_Click"/>
        <Grid Grid.Row="1">
            <Grid.RowDefinitions>
                <RowDefinition Height="Auto" />
                <RowDefinition Height="Auto" />
                <RowDefinition Height="Auto" />
                <RowDefinition Height="*" />
            </Grid.RowDefinitions>
            <TextBox x:Name="tb1" Grid.Row="0" Background="LightBlue" FontSize="24" Margin="4" />
            <TextBox x:Name="tb2" Grid.Row="1" Background="LightBlue" FontSize="24" Margin="4" />
            <TextBox x:Name="tb3" Grid.Row="2" Background="LightBlue" FontSize="24" Margin="4" />
            <Button x:Name="addButton" Grid.Row="3" Content="Add" Width="120" Height="80" Click="addButton_Click"/>
        </Grid>
    </Grid>
</Window>

image.png

namespace Demo9.WpfMVVM设计模式 {
    /// <summary>
    /// MainWindow.xaml 的交互逻辑
    /// </summary>
    public partial class MainWindow : Window {
        public MainWindow() {
            InitializeComponent();
        }

        private void addButton_Click(object sender, RoutedEventArgs e) {
            double num1 = double.Parse(tb1.Text);
            double num2 = double.Parse(tb2.Text);
            double re = num1 + num2;
            tb3.Text = re.ToString();
        }

        private void saveButton_Click(object sender, RoutedEventArgs e) {
            SaveFileDialog sfd = new SaveFileDialog();
            sfd.ShowDialog();
        }
    }
}

2. 客户要改需求

如果这时候客户不想要文本输入的方式来实现功能,想要以滑动的方式使用加法器。
如下:

<Window x:Class="Demo9.WpfMVVM设计模式.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:Demo9.WpfMVVM设计模式"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>
        <Menu>
            <MenuItem Header="_File">
                <MenuItem Header="_Save" Click="saveButton_Click" />
            </MenuItem>
        </Menu>
        <Grid Grid.Row="1">
            <Grid.RowDefinitions>
                <RowDefinition Height="Auto" />
                <RowDefinition Height="Auto" />
                <RowDefinition Height="Auto" />
                <RowDefinition Height="*" />
            </Grid.RowDefinitions>
            <Slider x:Name="slider1" Grid.Row="0" Background="LightBlue" Minimum="-100" Maximum="100" Margin="4" />
            <Slider x:Name="slider2" Grid.Row="1" Background="LightBlue" Minimum="-100" Maximum="100" Margin="4" />
            <Slider x:Name="slider3" Grid.Row="2" Background="LightBlue" Minimum="-100" Maximum="100" Margin="4" />
            <Button x:Name="addButton" Grid.Row="3" Content="Add" Width="120" Height="80" Click="addButton_Click" />
        </Grid>
    </Grid>
</Window>

image.png

namespace Demo9.WpfMVVM设计模式 {
    /// <summary>
    /// MainWindow.xaml 的交互逻辑
    /// </summary>
    public partial class MainWindow : Window {
        public MainWindow() {
            InitializeComponent();
        }

        private void addButton_Click(object sender, RoutedEventArgs e) {
            double num1 = slider1.Value;
            double num2 = slider1.Value;
            double re = num1 + num2;
            slider3.Value = re;
        }

        private void saveButton_Click(object sender, RoutedEventArgs e) {
            SaveFileDialog sfd = new SaveFileDialog();
            sfd.ShowDialog();
        }
    }
}

虽然这样我们就实现了,但是我们不仅改了界面还改了后台逻辑,很麻烦。万一客户又变一种样式,改的很烦这样就。

3. MVVM设计模式出场

那么,可不可以在用户需求变更的时候,在界面频繁变更的时候,让我们改代码不这么痛苦。
尽可能:更改界面是开放的,逻辑代码变更是闭合的,那么我们就使用MVVM设计模式。

首先把界面恢复到最开始的状态

<Window x:Class="Demo9.WpfMVVM设计模式.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:Demo9.WpfMVVM设计模式"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>
        <Button Content="Save" />
        <Grid Grid.Row="1">
            <Grid.RowDefinitions>
                <RowDefinition Height="Auto" />
                <RowDefinition Height="Auto" />
                <RowDefinition Height="Auto" />
                <RowDefinition Height="*" />
            </Grid.RowDefinitions>
            <TextBox x:Name="tb1" Grid.Row="0" Background="LightBlue" FontSize="24" Margin="4" />
            <TextBox x:Name="tb2" Grid.Row="1" Background="LightBlue" FontSize="24" Margin="4" />
            <TextBox x:Name="tb3" Grid.Row="2" Background="LightBlue" FontSize="24" Margin="4" />
            <Button x:Name="addButton" Grid.Row="3" Content="Add" Width="120" Height="80" />
        </Grid>
    </Grid>
</Window>

image.png

namespace Demo9.WpfMVVM设计模式 {
    /// <summary>
    /// MainWindow.xaml 的交互逻辑
    /// </summary>
    public partial class MainWindow : Window {
        public MainWindow() {
            InitializeComponent();
        }
    }
}

4. 使用MVVM模式

  • NotificationObject与数据属性
  • DelegateCommand与命令属性
  • View与ViewMode的交互(技术难点)

A. 建立几个文件夹

image.png

B. 创建 NotificationObject

在ViewModels文件夹下创建 具有通知能力对象 的这么一个类,所有ViewModel类的基类
Binding通过监听这个事件属性来更新绑定UI的控件的值。

namespace Demo9.WpfMVVM设计模式.ViewModels {
    internal class NotificationObject : INotifyPropertyChanged {
        public event PropertyChangedEventHandler PropertyChanged;

        public void RaisePropertyChanged(string propertyName) {
            if (PropertyChanged != null) {
                PropertyChanged.Invoke(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    }
}

C. 创建DelegateCommand

在项目里,新建一个文件夹Commands,再在该文件夹下创建 DelegateCommand类

namespace Demo9.WpfMVVM设计模式.Commands {
    internal class DelegateCommand : ICommand {
        public event EventHandler CanExecuteChanged;

        public bool CanExecute(object parameter) {
            if (this.CanExecuteFunc == null)
                return true;
            return this.CanExecuteFunc(parameter);
        }

        public void Execute(object parameter) {
            if(this.ExecuteAction == null)
                return;
            this.ExecuteAction(parameter);
        }

        public Action<object> ExecuteAction { get; set; }
        public Func<object, bool> CanExecuteFunc { get; set; }
    }
}

D. 给View建模

ViewModel的本质就是对应的View的建模
这里示例的本质就是:
2个值让用户可以输入,1个值给用户显示输出,1个命令让后台进行加法计算,还有另外1个命令可以做文件保存
——3个数据属性,2个命令属性

这里创建MainWindow对应的ViewModel的MainWindowsViewModel类

namespace Demo9.WpfMVVM设计模式.ViewModels {
    internal class MainWindowViewModel : NotificationObject {
        private double input1;
        public double Input1 {
            get { return input1; }
            set {
                input1 = value;
                this.RaisePropertyChanged("Input1");
            }
        }

        private double input2;
        public double Input2 {
            get { return input2; }
            set {
                input2 = value;
                this.RaisePropertyChanged("Input2");
            }
        }

        private double result;
        public double Result {
            get { return result; }
            set {
                result = value;
                this.RaisePropertyChanged("Result");
            }
        }

        public DelegateCommand AddCommand { get; set; }
    
        private void Add(object parameter) {
            this.Result = this.Input1 + this.Input2;
        }

        public MainWindowViewModel() {
            this.AddCommand = new DelegateCommand();
            this.AddCommand.ExecuteAction=new Action<object>(this.Add);
        }
    }
}

再在MainWindow.xaml文件下添加Binding
image.png
在MainWindow.xaml.cs添加DataContext
image.png
运行:成功实现!!!
image.png

E. 再添加 保存文件 这个命令

namespace Demo9.WpfMVVM设计模式.ViewModels {
    internal class MainWindowViewModel : NotificationObject {

        private double input1;
        public double Input1 {
            get { return input1; }
            set {
                input1 = value;
                this.RaisePropertyChanged("Input1");
            }
        }

        private double input2;
        public double Input2 {
            get { return input2; }
            set {
                input2 = value;
                this.RaisePropertyChanged("Input2");
            }
        }

        private double result;
        public double Result {
            get { return result; }
            set {
                result = value;
                this.RaisePropertyChanged("Result");
            }
        }

        public DelegateCommand AddCommand { get; set; }
        private void Add(object parameter) {
            this.Result = this.Input1 + this.Input2;
        }

        public DelegateCommand SaveFileCommand { get; set; }
        private void Save(object parameter) {
            SaveFileDialog sfd = new SaveFileDialog();
            sfd.ShowDialog();
        }

        public MainWindowViewModel() {
            this.AddCommand = new DelegateCommand();
            this.AddCommand.ExecuteAction = new Action<object>(this.Add);

            this.SaveFileCommand = new DelegateCommand();
            this.SaveFileCommand.ExecuteAction = new Action<object>(this.Save);
        }
    }
}

再在MainWindow.xaml添加保存文件的Binding
image.png
运行,成功实现!
image.png

F. 修改成滑块的界面实现该功能

这时候客户不想要文本输入的方式来实现功能,想要以滑动的方式使用加法器。
可以看到只需要让UI控件重新绑定,后台代码没有修改。效果依然实现。

<Window x:Class="Demo9.WpfMVVM设计模式.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:Demo9.WpfMVVM设计模式"
  mc:Ignorable="d"
  Title="MainWindow" Height="450" Width="800">
  <Grid>
    <Grid.RowDefinitions>
      <RowDefinition Height="Auto" />
      <RowDefinition Height="*" />
    </Grid.RowDefinitions>
    <Menu>
      <MenuItem Header="_File">
        <MenuItem Header="_Save" Command="{Binding SaveFileCommand}" />
      </MenuItem>
    </Menu>
    <Grid Grid.Row="1">
      <Grid.RowDefinitions>
        <RowDefinition Height="Auto" />
        <RowDefinition Height="Auto" />
        <RowDefinition Height="Auto" />
        <RowDefinition Height="*" />
      </Grid.RowDefinitions>
      <Slider x:Name="slider1" Value="{Binding Input1}" Grid.Row="0" Background="LightBlue" Minimum="-100" Maximum="100" Margin="4" />
      <Slider x:Name="slider2" Value="{Binding Input2}" Grid.Row="1" Background="LightBlue" Minimum="-100" Maximum="100" Margin="4" />
      <Slider x:Name="slider3" Value="{Binding Result}" Grid.Row="2" Background="LightBlue" Minimum="-100" Maximum="100" Margin="4" />
      <Button x:Name="addButton" Command="{Binding AddCommand}" Grid.Row="3" Content="Add" Width="120" Height="80" />
    </Grid>
  </Grid>
</Window>

image.png
可以看到只需要重新绑定,后台代码没有修改。效果依然实现。

标签:MVVM,double,private,MainWindow,设计模式,public
From: https://www.cnblogs.com/swbna/p/17437022.html

相关文章

  • 设计模式概述
    推荐文档:https://www.cnblogs.com/zhili/p/DesignPatternSummery.htmlhttps://www.runoob.com/design-pattern/design-pattern-tutorial.html为什么要使用设计模式?使用设计模式的根本原因是适应变化,为了增加代码复用率,是软件更具有维护性和可扩展性。设计原则单一职责原则......
  • 设计模式之备忘录(Memento)
    概述备忘录模式(MementoPattern),是行为型模式设计模式之一,该模式用于保存对象当前状态,并且在之后可以再次恢复到此状态。备忘录模式实现的方式需要保证被保存的对象状态不能被对象从外部访问,目的是为了保护被保存的这些对象状态的完整性以及内部实现不向外暴露,本篇博客,我们就来......
  • 设计模式-观察者模式(Observer)
    一、 观察者(Observer)模式观察者模式又叫做发布-订阅(Publish/Subscribe)模式、模型-视图(Model/View)模式、源-监听器(Source/Listener)模式或从属者(Dependents)模式。观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态上发生变化时,会通......
  • 设计模式-行为型设计模式
    责任链模式定义为请求创建一个接收此次请求的链适用场景一个请求的处理需要多个对象当中的一个或几个协作处理优点请求的发送者和接收者(请求的处理)解耦责任链可以动态组合缺点责任链太长或者处理时间过长,影响性能责任链有可能过多/**处理者--或者Approver*@author......
  • Simple Factory Pattern 简单工厂模式简介与 C# 示例【创建型】【设计模式来了】
     〇、简介1、什么是简单工厂模式?一句话解释:  客户类和工厂类严格分工,客户类只需知道怎么用,处理逻辑交给工厂类。简单工厂模式(SimpleFactoryPattern)是日常开发中常用的设计模式。其是一种简单的创建型模式,它通过一个工厂类来创建对象,客户端只需要知道如何使用工厂类,而不需......
  • Java设计模式-策略模式
    简介在软件开发中,设计模式是为了解决常见问题而提供的一套可重用的解决方案。策略模式(StrategyPattern)是其中一种常见的设计模式,它属于行为型模式。该模式的核心思想是将不同的算法封装成独立的策略类,使得它们可以相互替换,而不影响客户端的使用。策略模式与其他设计模式有一些......
  • javascript设计模式-享元
    这是一种优化性能代码的模式,最适合解决因创建大量类似对象而累及性能的问题。对于那些可能一连几天也不会重新加载的大型应用系统非常有用。它用于减少应用程序所需要数量,通过将对象内部划分为内在数据和外在数据两类来实现。管理享元外在数据有许多方法:1、数据库;2、组合模式(利用......
  • 《设计模式之禅》Multition_Pattern--多例模式
    多例模式嘿,咱们书接上回。单例模式就是每次只能有一个实例,那么多例模式就是可以有多个实例对象。那在中国历史上有没有这种事情发生过呢,嘿,你别说,还真有,就出现在明朝,那三国期间的算不算,不算,各自称帝,各有各的地盘,国号不同。大家还记得那首诗《石灰吟》吗?作者是谁?于谦,他是被谁杀死的?明......
  • 设计模式-软件设计原则
    开闭原则定义:一个软件实体如类,模块和函数应该对扩展开放,对修改关闭用抽象构建框架,用实现扩展细节优点:提高软件系统可复用性和可维护性依赖倒置原则定义:高层模块不应该依赖底层模块,二者都应该依赖其抽象抽象不应该依赖细节,细节应该依赖抽象针对接口编程,不要针对实现编程优......
  • Singleton 单例模式简介与 C# 示例【创建型】【设计模式来了】
     〇、简介1、什么是单例模式?一句话解释:  单一的类,只能自己来创建唯一的一个对象。单例模式(SingletonPattern)是日常开发中最简单的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。这种模式涉及到一个单一的类,该类负责创建自己的对象,同时......