WPF-MVVM架构

news2024/10/1 12:19:08

在WPF(Windows Presentation Foundation)开发中,MVVM(Model-View-ViewModel)是一种非常流行的设计模式,它旨在将应用程序的UI逻辑与业务逻辑和数据模型分离,从而提高代码的可维护性、可测试性和可扩展性。MVVM模式由三个核心部分组成:Model(模型)、View(视图)和ViewModel(视图模型)。

1. Model(模型)

Model代表应用程序的数据和业务逻辑。它通常包含数据字段、属性以及操作这些数据的方法。Model是独立于View和ViewModel的,意味着它不知道也不关心数据是如何被展示或修改的。Model层主要负责数据的存储、检索和验证等业务逻辑。

2. View(视图)

View是用户界面的表示层,负责展示数据。在WPF中,View通常是由XAML(可扩展应用程序标记语言)和后台代码(C#或VB.NET)组成的。XAML用于定义UI的布局和样式,而后台代码则用于处理用户交互。View通过数据绑定与ViewModel进行交互,但View本身不直接处理业务逻辑或数据访问。

3. ViewModel(视图模型)

ViewModel是Model和View之间的桥梁,它封装了与View交互的Model数据。ViewModel为View提供数据,并处理用户交互逻辑。ViewModel通常包含与View绑定的属性(这些属性通常与Model中的属性相对应),以及用于更新这些属性的命令(如按钮点击事件)。ViewModel还负责将Model的数据转换为View可以理解和展示的格式,并处理用户输入,将其转换为Model可以理解的格式。

MVVM的优势

  • 高内聚低耦合:Model、View和ViewModel之间的职责明确,相互之间的依赖关系降到最低,提高了代码的可维护性和可扩展性。
  • 易于测试:由于ViewModel不依赖于View,因此可以独立于UI进行单元测试。
  • 提高开发效率:设计师和开发人员可以并行工作,设计师可以专注于View的设计,而开发人员则专注于ViewModel和Model的实现。
  • 更好的用户体验:ViewModel可以处理复杂的用户交互逻辑,使得View层更加简洁,从而提供更好的用户体验。

实现MVVM

在WPF中实现MVVM通常需要使用一些辅助库,如Prism、Caliburn.Micro或MVVM Light等,这些库提供了实现MVVM模式所需的基础结构和工具。然而,即使没有这些库,你也可以通过WPF的数据绑定、命令和INotifyPropertyChanged接口等特性来手动实现MVVM模式。

阶段一:

<Grid>
    <StackPanel>
        <StackPanel Orientation="Horizontal" Margin="0 5 0 0">
            <TextBlock Text="第一个数:" Margin="0 0 10 0"/>
            <TextBox Name="textNumber1" Width="150"/>
        </StackPanel>
        <StackPanel Orientation="Horizontal" Margin="0 10 0 0">
            <TextBlock Text="第二个数:" Margin="0 0 10 0"/>
            <TextBox Name="textNumber2" Width="150"/>
        </StackPanel>
        <StackPanel Orientation="Horizontal" Margin="0 10 0 0">
            <TextBlock Text="结       果:" Margin="0 0 10 0"/>
            <TextBox Name="textResult" Width="150"/>
        </StackPanel>

        <Button x:Name="btnResult" Content="计算结果" Width="150" HorizontalAlignment="Left" Margin="10 15 0 0" Click="btnResult_Click"/>
    </StackPanel>

</Grid>
public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
    }

    private void btnResult_Click(object sender, RoutedEventArgs e)
    {
        this.textResult.Text = int.Parse(textNumber1.Text) + int.Parse(textNumber2.Text) + "";
    }
}

阶段二:

创建ViewModel文件

1.更改启动的路径

App.xaml文件 :  StartupUri="Views/MainWindow.xaml"

2.更改MainWindow.xaml文件
<Grid>
    <StackPanel>
        <StackPanel Orientation="Horizontal" Margin="0 5 0 0">
            <TextBlock Text="第一个数:" Margin="0 0 10 0"/>
            <TextBox  Width="150" Text="{Binding Number1}"/>
        </StackPanel>
        <StackPanel Orientation="Horizontal" Margin="0 10 0 0">
            <TextBlock Text="第二个数:" Margin="0 0 10 0"/>
            <TextBox  Width="150" Text="{Binding Number2}"/>
        </StackPanel>
        <StackPanel Orientation="Horizontal" Margin="0 10 0 0">
            <TextBlock Text="结       果:" Margin="0 0 10 0"/>
            <TextBox  Width="150" Text="{Binding Result}"/>
        </StackPanel>

        <Button x:Name="btnResult" Content="计算结果" Width="150" HorizontalAlignment="Left" Margin="10 15 0 0" Command="{Binding CalcCommand}"/>
    </StackPanel>

</Grid>
3.更改MainWindow.xaml.cs文件把视图模型对象给到界面绑定 
 public MainWindow()
 {
     InitializeComponent();
     //把视图模型对象给到界面绑定
     this.DataContext = new MainWindowViewModel(); 
 }
4.MainWindowViewModel编写
public class MainWindowViewModel:INotifyPropertyChanged
{
    private int _number1=10;
    public int Number1 {
        get { return _number1; }
        set{ _number1 = value;  }
    }

    private int _number2=16;
    public int Number2
    {
        get { return _number2; }
        set { _number2 = value;  }
    }

    private int _result;
    public int Result
    {
        get { return _result; }
        set { _result = value; OnPropertyChanged(nameof(Result)); }
    }


    //数值更改进行界面的同时
    public event PropertyChangedEventHandler? PropertyChanged;
    public void OnPropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }


    public CommandBase CalcCommand 
    {
        get => new CommandBase 
        { 
            DoExecte = new Action<object>(CalcResult)
        };
    }
    //真正需要执行的计算逻辑
    private void CalcResult(object obj)
    {
        this.Result = _number1 + _number2;
        Debug.Write("AAA");
    }

}
5.CommandBase通用类的编写,按钮控件按下触发
  public class CommandBase : ICommand
  {
      public event EventHandler? CanExecuteChanged;
      public Func<object, bool>? CanExecution {  get; set; }
      public Action<object>? DoExecte { get; set; }

      //IsEnabled="False",就不会发起操作
      public bool CanExecute(object? parameter)
      {
          if(CanExecution != null)
          {
              CanExecute(parameter);
          }
          return true;
      }


      //正在执行命令的方法
      public void Execute(object? parameter)
      {
          DoExecte!.Invoke(parameter!);
      }
  }

阶段三

将数据放入Model中

1.CommandBase
 public class CommandBase : ICommand
 {
     public event EventHandler? CanExecuteChanged;
     public Func<object, bool>? CanExecution {  get; set; }
     public Action<object>? DoExecte { get; set; }

     //IsEnabled="False",就不会发起操作
     public bool CanExecute(object? parameter)
     {
         if(CanExecution != null)
         {
             CanExecute(parameter);
         }
         return true;
     }


     //正在执行命令的方法
     public void Execute(object? parameter)
     {
         DoExecte!.Invoke(parameter!);
     }
 }
2.NotifyBase
public class NotifyBase:INotifyPropertyChanged
{
    //数值更改进行界面的同时
    public event PropertyChangedEventHandler? PropertyChanged;
    public void OnPropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}
3.MainWindowModel
 public class MainWindowModel : NotifyBase
 {
     private int _number1 = 10;
     public int Number1
     {
         get { return _number1; }
         set { _number1 = value; }
     }

     private int _number2 = 16;
     public int Number2
     {
         get { return _number2; }
         set { _number2 = value; }
     }

     private int _result;
     public int Result
     {
         get { return _result; }
         set { _result = value; OnPropertyChanged(nameof(Result)); }
     }

     private string _time = "8888-88-88 88:88:88";
     public string Time
     {
         get { return _time; }
         set { _time = value; OnPropertyChanged(nameof(Time)); }
     }

 }

4.MainWindowViewModel

public class MainWindowViewModel
{
    public MainWindowModel MainWindowModel {get; set;}=new MainWindowModel();

    public MainWindowViewModel()
    {
        Task.Run(async () =>
        {
            while (true)
            {
                await Task.Delay(500);
                MainWindowModel.Time = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
            }
        });
    }


    public CommandBase CalcCommand 
    {
        get => new CommandBase 
        { 
            DoExecte = new Action<object>(CalcResult)
        };
    }
    //真正需要执行的计算逻辑
    private void CalcResult(object obj)
    {
        MainWindowModel.Result = MainWindowModel.Number1 + MainWindowModel.Number2;
        Debug.Write("AAA");
    }

}
5.MainWindow.xaml
<Grid>
    <StackPanel>
        <StackPanel Orientation="Horizontal" Margin="0 5 0 0">
            <TextBlock Text="第一个数:" Margin="0 0 10 0"/>
            <TextBox  Width="150" Text="{Binding MainWindowModel.Number1}"/>
        </StackPanel>
        <StackPanel Orientation="Horizontal" Margin="0 10 0 0">
            <TextBlock Text="第二个数:" Margin="0 0 10 0"/>
            <TextBox  Width="150" Text="{Binding MainWindowModel.Number2}"/>
        </StackPanel>
        <StackPanel Orientation="Horizontal" Margin="0 10 0 0">
            <TextBlock Text="结       果:" Margin="0 0 10 0"/>
            <TextBox Name="Tresult"  Width="150" Text="{Binding MainWindowModel.Result}"/>
            <!--同步文本框中的文本-->
            <TextBlock Text="{Binding ElementName=Tresult ,Path=Text}" Margin="10 0 0 0"/>
            
        </StackPanel>

        <Button x:Name="btnResult" Content="计算结果" Width="150" HorizontalAlignment="Left" Margin="10 15 0 0" Command="{Binding CalcCommand}"/>
        <TextBlock Text="{Binding MainWindowModel.Time}" Width="150" Height="20" Margin="10"/>
    </StackPanel>

</Grid>
6.MainWindow.xaml.cs
   public MainWindow()
   {
       InitializeComponent();
       //把视图模型对象给到界面绑定
       this.DataContext = new MainWindowViewModel(); 
   }

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

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

相关文章

4.12.束搜索

束搜索 ​ 为了量化解码器的计算代价&#xff0c;用 y y y表示输出词表&#xff0c;其中包含 < e o s > <eos> <eos>&#xff0c;词表大小则为 ∣ y ∣ |y| ∣y∣&#xff0c;指定输出序列的最大词元数为 T ′ T T′&#xff0c;则我们的目标是从所有 O ( ∣…

同态加密和SEAL库的介绍(三)BFV - Batch Encoder

写在前面&#xff1a; 在上一篇中展示了如何使用 BFV 方案执行一个非常简单的计算。该计算在 plain_modulus 参数下进行&#xff0c;并且仅使用了 BFV 明文多项式中的一个系数。这种方法有两个显著的问题&#xff1a; 实际应用通常使用整数或实数运算&#xff0c;而不是模运算…

解决postGis无法打开的问题

问题 无法打开PostGIS PostGIS Bundle 3 for PostgreSQL x64 12 Shapefile and DBF Loader Exporter 弹出窗口 找不到libcrypto-1 postgis libcrypto libssl-1-x64等问题 解决方法 打开PostgreSQL安装目录下的Bin文件夹 查找缺少的文件 将其复制到 postgisgui 下 复制后即可…

网站建设网络公司如何选择

在选择网站建设网络公司时&#xff0c;需要考虑多个因素&#xff0c;以确保您的网站能够满足业务需求并取得成功。以下是一些建议&#xff0c;帮助您在选择网站建设网络公司时做出明智的决策。 首先&#xff0c;您应该考虑公司的经验和专业知识。选择一家有丰富经验的公司&…

实战从零开始实现Raft|得物技术

一、前言 Raft算法是一种分布式一致性算法&#xff0c;由Diego Ongaro和John Ousterhout在2013年提出。它主要用于分布式系统中&#xff0c;保证系统中的数据在多个节点间保持一致性。 Raft算法被广泛应用于众多分布式系统中&#xff0c;尤其是在需要强一致性保证的场景中&am…

【C++】-----多态及原理

目录 前言 一、是什么&#xff1f; 二、怎么样&#xff1f; Ⅰ、构成条件 Ⅱ、虚函数 Ⅲ、虚函数的重写 1.常规情况下 2.虚函数重写的三个例外 ①返回值的类型可以不同 ②析构函数的重写 ③子类虚函数可以不加virtual关键字(不建议) 3.override和final关键字 Ⅳ、重…

极米RS10 Plus VS当贝X5S Pro!最强客厅投影仪选当贝投影才是正解

不知道为什么&#xff0c;2024年的投影仪市场迭代迅猛&#xff0c;尤其是很多头部品牌小升级不断&#xff0c;机型后缀错综复杂让消费者更难下定决心做出抉择。而在今天又有一款新品极米RS10 Plus正式发布&#xff0c;同价位其实早前就有热门人气选手当贝X5S Pro坐镇&#xff0…

ChatGPT的封号和停止注册应对和常见问题丨出海笔记

ChatGPT "亚洲区封号"和“停止注册”的事情大家都听说过吧&#xff0c;我认为&#xff0c;官方有一定程度的“控频”&#xff0c;但并没有一杆子打死&#xff0c;更没有自媒体吹嘘的所谓封号和无法注册&#xff0c;因为我曾给朋友注册了2个以及升级plus成功&#xff…

MM 12 -采购- 成本中心采购

思维导图 说明 采购申请 手工或BPM接口创建 物料组&#xff1a; 必输 科目分配类别K &#xff0c;标签页会增加 科目分配 标签页 会计科目&#xff1a; 根据物料组带出 或者直接输入&#xff0c;根据情景。 成本中心需要填写。 采购订单 科目分配类别K &#xff0c;标签页会增…

【Windows】EFI系统盘重新安装操作系统遇到磁盘MBR分区解决办法

【Windows】EFI系统盘重新安装操作系统遇到磁盘MBR分区解决办法 1.背景2.问题3.解决 1.背景 本博客使用ventoy软件制作USB闪存启动盘。 相关博客&#xff1a; 【windows10】ventoy软件制作USB闪存启动盘-CentOS8 https://blog.csdn.net/jn10010537/article/details/123283985…

C到C++——C++基础

C是一种通用的、静态类型的、跨平台的编程语言。它是在1979年由Bjarne Stroustrup创建的&#xff0c;最初是作为C语言的扩展来支持面向对象编程。 C在保留C语言的特性的同时&#xff0c;添加了许多其他的功能&#xff0c;包括类、对象、继承、多态、模板等。这使得C成为了一种…

“金牌挑战——奥运知识大比拼”微信小程序线上知识竞赛答题活动复盘总结

一、活动背景 奥运会进行得如火如荼&#xff0c;为了弘扬奥运精神&#xff0c;激发公众对于奥林匹克运动的兴趣和热情&#xff0c;我们特别策划了“金牌挑战——奥运知识大比拼”线上知识竞赛活动。本次活动依托微信小程序&#xff0c;通过趣味性和互动性强的知识竞答&#xf…

SOPHGO算能科技BM1684盒子占用空间满的问题解决

目录 1 问题由来 2 问题排查与解决 1 问题由来 安装软件的时候发现&#xff0c;软件根本安装不上了&#xff0c;用df -h看到根目录已经满了 rootbm1684:~# df -h Filesystem Size Used Avail Use% Mounted on overlay 5.8G 5.7G 0 100% / devtmpfs …

【实战】MFC客户端Python后端之仿造QQ聊天

项目概述 这里介绍一个很多年以前做的一个小项目&#xff0c;新手小白可以参考学习。本项目旨在开发一个功能丰富的即时通讯及聊天室系统&#xff0c;类似于QQ&#xff0c;具备客户端与服务端通讯、多人聊天室、界面友好度、一对一聊天、通讯内容加密、服务端与数据库交互等功能…

十八.核心动画 - 使用CAGradientLayer图层构建渐变视图

引言 在现代的UI设计中&#xff0c;渐变色和圆角已经成为了不可或缺的元素。无论是应用程序的背景&#xff0c;按钮&#xff0c;还是图标&#xff0c;这些设计趋势不仅使界面更加美观&#xff0c;还能提升用户体验。特别是渐变色&#xff0c;它通过颜色的平滑过渡&#xff0c;…

如何利用绩效考核来强化员工对TPM的参与度?

TPM&#xff08;Total Productive Maintenance, 全面生产维护&#xff09;作为一种追求生产系统效率最大化的管理模式&#xff0c;其核心在于通过全员参与和持续改进&#xff0c;实现设备综合效率的最大化。然而&#xff0c;要让这一理念深入人心&#xff0c;并转化为员工的日常…

图片转为pdf怎么弄?亲测有效的8个pdf转换方法安利

图片转PDF怎么弄&#xff1f;在日常的办公生活中&#xff0c;我们经常会需要处理一些文档格式转换难题&#xff0c;图片转成PDF格式就是其中一个&#xff0c;图片转换成PDF格式的话&#xff0c;方便我们传输分享&#xff0c;毕竟现在PDF格式凭借着自身的稳定性和可移植性已经成…

李晨晨的嵌入式学习 DAY20

今天主要对zuot学习函数进行了补充 一&#xff0c;文件IO函数 1.fileno函数 类型转换函数 函数原型&#xff1a;int fileno(FILE *stream); 功能&#xff1a;fileno函数用于取得参数stream指定的文件流所使用的文件描述符。文件描述符是一个非负整数&#xff0c;用于在底层…

C/C++开发,opencv光流法跟踪特征点

目录 一、Lucas-Kanade光流法 1.1cv::ORB特征点提取方法 1.2 cv::calcOpticalFlowPyrLK函数 二、完整案例实现 2.1 程序代码 2.2 程序编译及输出 2.3 读取视频文件方式补充 一、Lucas-Kanade光流法 在 OpenCV 中&#xff0c;使用 特征检测器(例如ORB ,Oriented FAST and…

基于深度学习的地磁活动、扰动预测模型

注&#xff1a;包括SYM-H Index和Storm Intensity index A transformer-based framework for predicting geomagnetic indices with uncertainty quantification Journal of Intelligent Information Systems 18 November 2023 A transformer-based framework for predicting…