MVVM架构

介绍

MVVM是Model-View-ViewModel的简写。它本质上就是MVC的改进版。MVVM模式有助于将应用程序的业务和表示逻辑与用户界面 (UI) 清晰分离。 保持应用程序逻辑和UI之间的清晰分离有助于解决许多开发问题,并使应用程序更易于测试、维护和演变。 它还可以显著提高代码重用机会,并允许开发人员和UI设计人员在开发应用各自的部分时更轻松地进行协作。

组成部分

MVVM模式,应用的UI以及基础表示和业务逻辑被分成三个独立的类:

视图(View),用于封装UI和UI逻辑, 也就是交互界面,接受用户的输入和展示数据;

视图模型(ViewModel),用于封装表示逻辑和状态;

模型(Model),用于封装应用的业务逻辑和数据。

优势

低耦合:View可以独立于Model变化和修改,一个ViewModel可以绑定到不同的”View”上,当View变化的时候Model可以不变,当Model变化的时候View也可以不变。

提高代码重用:可以把一些视图逻辑放在一个ViewModel里面,让很多View重用这段视图逻辑;

独立开发:业务开发人员可以专注于业务逻辑和数据的开发,界面开发人员可以专注于页面的开发。

使用场景

以下是MVVM架构的应用场景:

场景描述
复杂的用户界面当应用程序具有复杂的用户界面和大量的交互时,MVVM可以提供更好的分层和组织代码的方式。
需要频繁变更的用户界面如果应用程序的用户界面需要频繁变更,MVVM的数据绑定机制可以简化界面更新的过程,提高开发效率。
需要同时支持多个平台或设备的应用程序MVVM的解耦性和可测试性使其非常适合开发需要在多个平台或设备上运行的应用程序,如移动应用和桌面应用。
需要重用代码和逻辑的应用程序MVVM的分离关注点和数据绑定机制使得代码和逻辑的重用更加容易,从而减少了代码的重复编写。
需要高可维护性和可扩展性的应用程序MVVM的分层结构和清晰的职责分离使得应用程序更易于维护和扩展,有利于团队合作和长期项目的发展。 

搭建MVVM架构

1、首先需要新建一个项目,再创建Views,ViewModels,Models 三个文件夹,就是一个基本架构。

2、将我们写的xaml页面放在Views目录下,一般就是命名为:xxxView,然后与之对应的视图模型命令为xxxViewModel放在ViewModels目录下,另外将需要的数据模型放置在Models目录下。

3、再者需要创建一些辅助类的文件目录,一般会创建Resources用于存放一些资源如样式,字体,图片等等,创建一个Helper或者Common的目录,用于存放一些公用的方法类或者帮助类。

实现INotifyPropertyChanged接口

实现属性变更的通知 实现页面指令

public class UserViewModel : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler? PropertyChanged;
    
        private User user; // 私有的用户对象
        public string Name { 
            get { return user.Name; } 
            set { 
                user.Name = value; 
                PropertyChanged(this, new PropertyChangedEventArgs("Name")); 
            } 
        }
    
        public int Age {  
            get { return user.Age; } 
            set { 
                user.Age = value; 
                PropertyChanged(this, new PropertyChangedEventArgs("Age")); 
            } 
        }
    }

实现ICommand接口命令

自定义指令

public class MyCommand : ICommand
    {
        //1 事件成员 状态发生变化的时候事件,
        public event EventHandler CanExecuteChanged;
    
        //2 命令是否是可执行状态 参数就是xaml文件通过Commandparameter属性传递过来
        public bool CanExecute(object parameter)
        {
            if (NengBuNengZhiXing == null) return true; //如果外部没有控制状态的函数,默认指令可执行
            // 如果有指令能不能执行的函数,NengBuNengZhiXing返回值为true或者false
    
            return NengBuNengZhiXing.Invoke(parameter);
        }
    
        //3 命令触发之后执行函数 参数就是xaml文件通过Commandparameter属性传递过来
        public void Execute(object parameter)
        {
            this.ChuFaMingLingFun.Invoke(parameter);
        }
    
        // 4
        //定义委托接受命令触发之后的函数 作为Execute要调用的
        Action<object> ChuFaMingLingFun;
        //接受判断命令是否能够执行的函数 ,作为CanExecute的判断条件
        Func<object, bool> NengBuNengZhiXing;
    
        //5 给上面俩个变量赋值 通过构造函数进行赋值
        public MyCommand(Action<object> a1, Func<object, bool> a2)
        {
            this.ChuFaMingLingFun = a1;
            this.NengBuNengZhiXing = a2;
    
        }
        //6 如果可执行的状态的发生变化了 触发CanExecuteChanged事件 在外部修改状态的时候调用
        public void OnCanExecuteChange()
        {
            CanExecuteChanged(this, EventArgs.Empty);
        }
    }

使用ICommand时参数的传递和接收

传递

传递参数时在UI界面中使用 CommandParamete属性进行传递

传递字符串属性

    <Button Height="40" Command="{Binding M1}"
            CommandParameter="Red"></Button>

传递对象属性(传递控件)
RelativeSource传递方式

RelativeSource方式可以绑定父级控件进行传递 祖先:FindAncestor

    <Button Width="100"
                Command="{Binding Cancel}"
                <!--传递对象参数Windows窗体-->
                CommandParameter="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=Window}}"
                Height="40"
                Margin="200,100,0,0">取消</Button>

ElementName传递方式

FindAncestor方式可以绑定指定控件的Name属性进行传递

    <Button Name="B">保存</Button>
    <Button Width="100"
            Command="{Binding Cancel}"
            CommandParameter="{Binding ElementName=B}"
            Height="40"
            Margin="200,100,0,0">取消</Button>

接收参数

接收参数时,是在IComand命令类中的条件函数中和回调函数中接收

接收的类型对应着传递的类型

    public bool CanExecute(object parameter)
    {
        if (CanWork == null) return true;
        return CanWork.Invoke(parameter);
    }
    
    public void Execute(object parameter)
    {
        this.Work.Invoke(parameter);
    }

ViewModel视图模型中逻辑和状态,

场景:

INotifyPropertyChanged接口和ICommand接口命令搭配使用,绑定指令和接收指令参数,展示模型数据。

UI窗体页面 标签布局
    <Grid>
        <!--Name-->
        <TextBox Text="{Binding Name}" Width="200" Height="40" Margin="-200,0,0,0" ></TextBox>
    
        <!--Age-->
        <TextBox Text="{Binding Age}"
                   Width="200"
                   Height="40"
                   Margin="-200,100,0,0"></TextBox>
        <TextBox Text="{Binding Info}"
                 Width="200"
                 Height="40"
                 Margin="-200,200,0,0"></TextBox>
    
        <Button Width="100"
                Command="{Binding Save}"
                Height="40"
                Margin="200,0,0,0">保存</Button>
        <Button Width="100"
                Command="{Binding Cancel}"
                <!--传递对象参数Windows窗体-->
                CommandParameter="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=Window}}"
                Height="40"
                Margin="200,100,0,0">取消</Button>
    </Grid>
    
    
    
    
    
    
    在Model模型文件创建存储数据的类
    public class User:INotifyPropertyChanged
    {
        private string _name = "张三";
        public string Name 
        {
            get => _name;
            set 
            {
                _name = value;
                PropertyChanged(this,new PropertyChangedEventArgs("Name"));
            }
        }
    
        private int _age ;
    
        public int Age
        {
            get => _age; 
            set
            {
                _age = value;
                PropertyChanged(this, new PropertyChangedEventArgs("Age"));
            }
        }
    
    
        public event PropertyChangedEventHandler? PropertyChanged;
    }
    
    
    
    
    
    
    
    在ViewModel文件实现后台视图模型逻辑
    public class UserViewModel : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler? PropertyChanged;
    
        private User user; // 私有的用户对象(模型类对象)
        public string Name
        {
            get { return user.Name; }
            set
            {
                user.Name = value;
                PropertyChanged(this, new PropertyChangedEventArgs("Name"));
            }
        }
    
        public int Age
        {
            get { return user.Age; }
            set
            {
                user.Age = value;
                PropertyChanged(this, new PropertyChangedEventArgs("Age"));
            }
        }
    
        public string Info
        {
            get { return $"Name:{Name} Age:{Age}"; }
            set { Info = value; }
        }
    
        public void OnpropertyChanged(string n1)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(n1));
            }
        }
    
        // 指令的使用,在对应viewmodel的构造函数中进行使用
        public UserViewModel()
        {
            user = new User();
            Save = new MyCommand(BaoCun); // 保存的指令
            Cancel = new MyCommand(QuXiao); // 取消指令
        }
        public MyCommand Save { get;private set ; }
        public MyCommand Cancel { get;private set ; }
        public void BaoCun(object o)
        {
            MessageBox.Show("保存数据");
            // 数据变化进行
            OnpropertyChanged("Info");
        }
        public void QuXiao(object o)
        {
            // 关闭窗体
            var window = o as Window;
            if (window != null)
            {
                window.Close();
            }
        }
    }
    
    public class MyCommand : ICommand
    {
        public event EventHandler? CanExecuteChanged;
    
        public bool CanExecute(object? parameter)
        {
            if (f1 == null) return true;
            return f1.Invoke(parameter) == true;
        }
    
        public void Execute(object? parameter)
        {
            a1.Invoke(parameter);
        }
    
        Action<object> a1; // 在Execute去调用
        Func<object,bool> f1; // 在CanExecute去调用
    
        // 在构造函数里面给a1和f1赋值
        public MyCommand(Action<object> a1) : this(a1,null)
        {
            this.a1 = a1;
        }
        // 可以传递俩个参数,MyCommand(f1,f2);
        public MyCommand(Action<object> a1,Func<object,bool> f1)
        {
            this.a1 = a1;
            this.f1 = f1;
        }
    
        // 当修改指令状态时候 需要手动调用该函数
        public void OnCanExeutedChanged()
        {
            CanExecuteChanged(this, EventArgs.Empty);
        }
    
    }
    
    
    
    
    
    
    
    在Windows后台cs中进行数据绑定
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            this.DataContext = new UserViewModel();
        }
    }

  • 31
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Android MVVM 架构是一种基于 Model-View-ViewModel(模型-视图-视图模型)设计模式的架构,它旨在实现 Android 应用程序的高内聚、低耦合、可测试性和可维护性。在 MVVM 架构中,View(视图)和 ViewModel(视图模型)之间通过数据绑定进行通信,ViewModel(视图模型)和 Model(模型)之间通过业务逻辑进行通信。 MVVM 架构将应用程序分为三个部分: 1. Model:处理数据和业务逻辑,与数据库、网络、API 等打交道。 2. View:负责显示 UI、处理用户输入和事件,是用户与应用程序交互的界面。 3. ViewModel:作为 View 和 Model 之间的桥梁,处理视图逻辑、业务逻辑和数据绑定,将 Model 中的数据转换为 View 可以显示的数据。 在 MVVM 架构中,View 和 ViewModel 之间通过数据绑定实现双向通信,View 可以观察 ViewModel 中的数据变化,并及时更新 UI,同时用户的操作也会触发 ViewModel 中的业务逻辑,从而实现 View 和 Model 的解耦。 MVVM 架构的优点包括: 1. 高内聚、低耦合:各个模块之间的职责清晰明确,代码结构清晰,易于维护。 2. 可测试性:ViewModel 和 Model 都是纯 Java 类,不依赖 Android 系统,易于编写单元测试。 3. 可维护性:MVVM 架构使得代码易于维护和扩展,添加新功能时可以只修改 ViewModel 或 Model,而不影响 View。 总之,MVVM 架构是一种适用于 Android 应用程序的高效、可维护的架构,可以提高开发效率、代码质量和用户体验。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值