WPF中MVVM架构学习笔记

news2024/11/18 11:40:08

MVVM架构是一种基于数据驱动的软件开发架构,它将数据模型(Model)、视图(View)和视图模型(ViewModel)三者进行分离,使得开发者可以更加专注于各自领域的开发。其中,Model负责存储和管理数据,View负责数据的展示,而ViewModel则作为Model和View之间的桥梁,负责数据的双向绑定和业务逻辑的处理。

MVVM架构的特点

  1. 数据驱动:MVVM架构的核心是数据驱动,当数据发生变化时,视图会自动更新,反之亦然。这种双向数据绑定的机制大大减少了开发者在视图和数据之间手动同步的工作量。
  2. 分离关注点:通过将Model、View和ViewModel三者进行分离,开发者可以更加专注于各自领域的开发,提高了代码的可维护性和可重用性。
  3. 视图与业务逻辑解耦:ViewModel负责处理业务逻辑,而View只负责展示数据,这种设计使得视图和业务逻辑之间的耦合度大大降低,提高了代码的可读性和可测试性。

 实现效果 :

阶段一:代码创建文件放置,搭建出INotifyPropertyChanged进行前后台数据更新

<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="100"/>
        <RowDefinition Height="150"/>
        <RowDefinition/>
        <RowDefinition/>
    </Grid.RowDefinitions>
    <Border BorderThickness="1" BorderBrush="Black" Grid.Row="1" Height="30" Width="200" VerticalAlignment="Top" >
        <TextBox  Text="{Binding UserName}"/>
    </Border>

    <Border BorderThickness="1" BorderBrush="Black" Grid.Row="1" Height="30" Width="200" VerticalAlignment="Top" Margin="0,40,0,0"  >
        <TextBox Text="{Binding PassWord}" />
    </Border>
    <Button Grid.Row="1" Height="30" Width="200" VerticalAlignment="Bottom" Content="按钮" Click="Button_Click"/>

 



</Grid>
namespace WpfApp_libarymassage
{
    /// <summary>
    /// MainWindow.xaml 的交互逻辑
    /// </summary>
    public partial class MainWindow : Window, INotifyPropertyChanged
    {
       
        public MainWindow()
        {
            this.DataContext = this;
            InitializeComponent();
         
        }


        private string _UserName;
        public string UserName
        {
            get { return _UserName; }
            set { _UserName = value;
                OnPropertyChanged("UserName");
            }
        }

        private string _PassWord;
        public string PassWord
        {
            get { return _PassWord; }
            set { _PassWord = value;
                OnPropertyChanged(PassWord);
            }
        }




        public event PropertyChangedEventHandler PropertyChanged;
        protected void OnPropertyChanged(string propertyName)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
        }



        private void Button_Click(object sender, RoutedEventArgs e)
        {
            //string useName = textUserName.Text;
            //string passWord = textPassWord.Text;
            
            if (UserName == "AA" && PassWord == "123456" )
            {
                MessageBox.Show("Loding Successful");
            }
            else
            {
                MessageBox.Show("Load Fail");
                UserName = "";
                PassWord = "";
            }

        }
    }


}

阶段二:创建Model和ViewModel文件,降低数据的关联

LoginModel.cs文件

public class LoginModel : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;
    protected void OnPropertyChanged(string propertyName)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
    }


    private string _UserName;
    public string UserName
    {
        get { return _UserName; }
        set
        {
            _UserName = value;
            OnPropertyChanged("UserName");
        }
    }

    private string _PassWord;
    public string PassWord
    {
        get { return _PassWord; }
        set
        {
            _PassWord = value;
            OnPropertyChanged(PassWord);
        }
    }
}

LoginViewModel.cs

 public class LoginViewModel
 {
     private LoginModel _loginM; //创建LoginModel类型的变量_loginM
     public LoginModel LoginM   
     {
         get { 
             if (_loginM == null)   //如果没有实列化LoginModel,实列化LoginModel
                 _loginM = new LoginModel();
             return _loginM; }
         set { _loginM = value; }
     }
 }

XAM文件 

 public partial class MainWindow : Window
 {
     LoginViewModel loginViewModel; //创建变量LoginViewModel类型的变量loginViewModel
     public MainWindow()
     {         
         loginViewModel = new LoginViewModel(); //loginViewModel进行实列化
         this.DataContext = loginViewModel;    //绑定上下文
         InitializeComponent();

     }



     private void Button_Click(object sender, RoutedEventArgs e)
     {
         //因为我们实列话了LoginViewModel(),绑定的的变量是在LoginViewModel中的LoginM中
         //所以变量连接为loginViewModel.LoginM.UserName
         if (loginViewModel.LoginM.UserName == "AA" && loginViewModel.LoginM.PassWord == "123456" )
         {
             MessageBox.Show("Loding Successful");
         }
         else
         {
             MessageBox.Show("Load Fail");
             loginViewModel.LoginM.UserName = "";
             loginViewModel.LoginM.PassWord = "";
         }

     }
 }
  <Border BorderThickness="1" BorderBrush="Black" Grid.Row="1" Height="30" Width="200" VerticalAlignment="Top" >
      <TextBox  Text="{Binding LoginM.UserName}"/>
  </Border>

  <Border BorderThickness="1" BorderBrush="Black" Grid.Row="1" Height="30" Width="200" VerticalAlignment="Top" Margin="0,40,0,0"  >
      <TextBox Text="{Binding LoginM.PassWo

阶段三:将按钮放入ViewModel中

ICommand接口调用

RelayCommander.cs

internal class RelayCommander:ICommand
{
    readonly Func<bool> _canExecute; //命令是否能够执行
    readonly Action _execute; //命令需要执行的方法
    public RelayCommander(Action action, Func<bool> canExecute)
    {
        _execute =action;
        _canExecute =canExecute;
    }

    public bool CanExecute(object parameter)
    {
        if (_canExecute != null)
        {
            return true;
        }
        return _canExecute();
    }

    public void Execute(object parameter)
    {
        _execute();
    }

    public event EventHandler CanExecuteChanged
    {
        add
        {
            if (_canExecute != null)
            {
                CommandManager.RequerySuggested += value;
            
            }
        }
        remove
        {
            if ( _canExecute != null)
            {
                CommandManager.RequerySuggested -= value;
            }
        }
    }
}

在ViewModel中调用接口

public class LoginViewModel
{
    private LoginModel _loginM; //创建LoginModel类型的变量_loginM
    public LoginModel LoginM   
    {
        get { 
            if (_loginM == null)   //如果没有实列化LoginModel,实列化LoginModel
                _loginM = new LoginModel();
            return _loginM; }
        set { _loginM = value; }
    }


    //登录按钮方法
    void LoginFunc()
    {
        if (LoginM.UserName == "AA" && LoginM.PassWord == "123456")
        {
            MessageBox.Show("Loding Successful");
        }
        else
        {
            MessageBox.Show("Load Fail");
            LoginM.UserName = "";
            LoginM.PassWord = "";
        }
    }

    bool CanLoginExcute() { return true; }
    //命令绑定至按钮
    public ICommand LoginButton   //LoginButton参数为按钮Command绑定的参数
    { 
        get
        {
            return new RelayCommander(LoginFunc, CanLoginExcute);
        }
    
    }


}

xaml

public partial class MainWindow : Window
{
    LoginViewModel loginViewModel; //创建变量LoginViewModel类型的变量loginViewModel
    public MainWindow()
    {         
        loginViewModel = new LoginViewModel(); //loginViewModel进行实列化
        this.DataContext = loginViewModel;    //绑定上下文
        InitializeComponent();

    }

}
<Button Grid.Row="1" Height="30" Width="200" VerticalAlignment="Bottom" Content="按钮" Command="{Binding LoginButton}"/>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1692528.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

C++入门:从C语言到C++的过渡(2)

目录 1.缺省参数 1.1缺省参数的概念 1.2缺省参数的分类及使用 1.3注意点 2.函数重载 2.1函数重载的定义 2.2函数重载的情况分类 2.3注意 2.4函数名修饰规则 3.引用 3.1引用的概念 3.2注意事项 3.3常引用 4.4引用的使用场景 4.4.1作为函数的参数 4.4.2做函数返回…

计算机网络安全控制技术

1.防火墙技术 防火墙技术是近年来维护网络安全最重要的手段&#xff0c;但是防火墙不是万能的&#xff0c;需要配合其他安全措施来协同 2.加密技术 目前加密技术主要有两大类&#xff1a;对称加密和非对称加密 3.用户识别技术 核心是识别网络者是否是属于系统的合法用户 …

CSS基础(第二天)

Emmet语法 快速生成HTML结构语法 1. 生成标签 直接输入标签名 按tab键即可 比如 div 然后tab 键&#xff0c; 就可以生成 <div></div> 2. 如果想要生成多个相同标签 加上 * 就可以了 比如 div*3 就可以快速生成3个div 3. 如果有父子级关系的标签&#xff0c;可以…

进制转换【野路子改造】

非科班&#xff0c;一直都是自己的野路子&#xff0c;现在要回炉重造 十进制->二进制 基本思想&#xff1a; 开始写的&#xff08;80%&#xff09;&#xff1a; #include<stdio.h> using namespace std; int main(){ int n; scanf("%d",&n); int a[1…

Linux(Ubuntu)下MySQL5.7的安装

文章目录 1.看系统本身有没有MySQL2.安装MySQL3.登录MySQL4.修改配置文件my.cnf/mysqld.cnf5.开启远程访问功能5.1 允许其他主机通过root访问数据库5.2 Ubuntu下配置文件修改说明 1.看系统本身有没有MySQL mariadb也是mysql所以要先检查一下系统有没有MySQL 我这台机子是新机子…

FreeRTOS_任务通知_学习笔记

原文链接 任务通知 使用队列、信号量、事件组等等方法时&#xff0c;并不知道对方是谁。使用任务通知时&#xff0c;可以明确指定&#xff1a;通知哪个任务。 任务通知结构体中只有一个任务通知值&#xff0c;只能保持一个数据。 数据智能给目标任务独享。 任务通知只能一个…

win10右键没有默认打开方式的选项的处理方法

问题描述 搞了几个PDF书籍学习一下&#xff0c;不过我不想用默认的WPS打开&#xff0c;因为WPS太恶心人了&#xff0c;占用资源又高。我下载了个Sumatra PDF&#xff0c;这时候我像更改pdf文件默认的打开程序&#xff0c;发现右击没有这个选项。 问题解决 右击文件–属性–…

误差反向传播简介与实现

误差反向传播 导语计算图反向传播链式法则 反向传播结构加法节点乘法节点 实现简单层加法乘法 激活函数层实现ReLUSigmoid Affine/Softmax层实现Affine基础版批版本 Softmax-with-Loss 误差反向传播实现梯度确认总结参考文献 导语 书上在前一章介绍了随机梯度下降法进行参数与…

C语言 控制台API函数

目录 前言1. 句柄 HANDLE2. 控制台API结构体2.1 坐标结构 COORD2.2 光标信息结构 CONSOLE_CURSOR_INFO2.3 控制台屏幕缓冲区信息结构 CONSOLE_SCREEN_BUFFER_INFO 3. 控制台API函数3.1 获取句柄 GetStdHandle3.2 获取光标信息 GetConsoleCursorInfo3.3 设置光标信息SetConsoleC…

达梦8 RLOG_COMPRESS_LEVEL参数对系统的影响

测试环境是一套主备达梦数据库。下面在主备库分别设置参数进行测试 测试一、 主库设置RLOG_COMPRESS_LEVEL9&#xff0c;备库设置为0。 分别删除主备库的归档日志后执行测试脚本 #当前时间 date disql SYSDBA/SYSDBA:1807 <<EOF #显示归档大小 select sum(free)/1024…

win10无权禁用任务计划程序中的任务

问题说明 最近被win10的自动频繁更新搞得难受&#xff0c;发誓要彻底禁用这个家伙&#xff0c;于是网上找了教程执行&#xff0c;发现执行到禁用windows update计划任务时&#xff0c;提示&#xff1a; 这特么windows这个辣鸡系统&#xff0c;限制还真多&#xff01;&#xf…

❤ Vscode和Idea都可以使用的-AI插件(官方-百度出的)

❤ Vscode和Idea都可以使用的-AI插件&#xff08;官方-百度出的&#xff09; 最新AI特别火&#xff0c;给大家推荐一下最新出的VScode插件&#xff0c;辅助我们写代码&#xff01; 1、下载地址&#xff1a; > https://comate.baidu.com/zh/shopping?inviteCodefkzlak8f …

HarmonyOS-MPChart绘制一条虚实相接的曲线

本文是基于鸿蒙三方库mpchart&#xff08;OpenHarmony-SIG/ohos-MPChart&#xff09;的使用&#xff0c;自定义绘制方法&#xff0c;绘制一条虚实相接的曲线。 mpchart本身的绘制功能是不支持虚实相接的曲线的&#xff0c;要么完全是实线&#xff0c;要么完全是虚线。那么当我…

嵌入式单片机启动地址映射关系

一、内核只会从0地址启动 1.0地址第一个字是sp栈指针,第二个字是Reset_Handler入口,参考图1中启动代码中的中断向量表。具体使用流程参考图2(参考自野火) 图1 图2 2.0地址映射以后,软件上使用0地址访问的空间是映射到的器件的空间 3.0地址映射只会影响单个器件上的地址,…

【C++】09.vector

一、vector介绍和使用 1.1 vector的介绍 vector是表示可变大小数组的序列容器。就像数组一样&#xff0c;vector也采用的连续存储空间来存储元素。也就是意味着可以采用下标对vector的元素进行访问&#xff0c;和数组一样高效。但是又不像数组&#xff0c;它的大小是可以动态改…

2024/5/25 英语每日一段

Alex Bols of the GuildHE group, representing 60 universities and colleges, said: “As the financial health of the higher education sector becomes ever more challenging, the need for a long-term funding solution becomes ever more urgent. “The increasing co…

鸿蒙HarmonyOS实战-Stage模型(信息传递载体Want)

&#x1f680;前言 应用中的信息传递是为了实现各种功能和交互。信息传递可以帮助用户和应用之间进行有效的沟通和交流。通过信息传递&#xff0c;应用可以向用户传递重要的消息、通知和提示&#xff0c;以提供及时的反馈和指导。同时&#xff0c;用户也可以通过信息传递向应用…

Prometheus+Grafana监控服务器、mysql数据库并配置报警规则推送邮箱

文章目录 一、安装prometheus1.1下载1.2 安装1.3 开机启动1.4 验证 二、安装 Grafana2.1 下载2.2 安装2.3 启动2.4 验证 三、安装服务器监控 node_exporter3.1 下载3.2 安装3.3 设置 node_exporter 系统服务3.4 设置开机自动启动3.5 验证3.6配置Prometheus3.7 修改 Prometheus …

海外新闻媒体发稿,PR稿件海外投稿,国外软文宣发-需综合考虑发布平台/内容质量/SEO策略/目标受众/发布时间/效果监控以及媒体关系等多个方面

发布新闻稿是提升品牌知名度和影响力的重要手段。以下是一些在国外新闻稿发布的干货分享&#xff0c;帮助你更有效地进行海外PR发稿。 1. 选择合适的发布平台 选择一个合适的新闻稿发布平台是关键&#xff0c;不同的平台有不同的覆盖范围和目标受众。以下是一些推荐的平台&am…

Java进阶学习笔记8——单继承、Object类、方法重写

Java 是单继承的&#xff0c;Java中的类不支持多继承&#xff0c;但是支持多层继承。 Object类是所有类的父类。 Java不支持多类继承&#xff1a; Java支持多层继承&#xff1a; 反证法&#xff1a; Object类&#xff1a; Object类是java所有类的祖宗类&#xff0c;我们写的任…