WPF12-MVVM

目录

  • [1. 什么是MVVM](#1. 什么是MVVM)
  • [2. 实现简单MVVM](#2. 实现简单MVVM)
    • [2.1. Part 1](#2.1. Part 1)
    • [2.2. Part 2](#2.2. Part 2)

1. 什么是MVVM

MVVMModel-View-ViewModel 的缩写,是一种用于构建用户界面的设计模式,是一种简化用户界面的事件驱动编程方式。

MVVM 的目标是实现用户界面和业务逻辑之间的彻底分离,以便更好地管理和维护应用程序,并提供更好的可测试性和可扩展性。

MVVM 模式包含以下三个核心组件:

Model(模型):Model 代表应用程序的数据和业务逻辑。它负责存储和管理数据,并且通常不包含任何与用户界面相关的代码。Model 可以是数据实体、数据库访问类、服务类等。

View(视图):View 是用户界面的可视化表示,通常由 XAML 文件定义。它负责展示数据给用户,并捕获用户输入。View 并不处理业务逻辑,而是通过绑定和命令将用户操作传递给 ViewModel。

ViewModel(视图模型):ViewModel 是 View 和 Model 之间的桥梁,负责处理 View 与 Model 之间的交互。它将 Model 中的数据转换为 View 所需的数据,并处理用户输入、命令和其他交互逻辑。ViewModel 通常实现了 INotifyPropertyChanged 接口,用于通知 View 当数据发生变化时进行更新。

MVVM 的基本原则是让 View 和 Model 完全解耦,它们之间通过 ViewModel 进行通信。View 通过数据绑定将 ViewModel 中的数据展示给用户,通过命令绑定将用户的操作传递给 ViewModel。ViewModel则通过数据绑定和命令绑定将用户输入转换为对 Model 的操作,从而实现业务逻辑的处理。

回到 WPF 里,View就是用xaml描绘的页面,负责与用户交互,响应用户操作,展示数据给用户;ViewModel负责收集需要绑定的数据和命令,通过 View 的 DataContext 属性绑定到 View,同时处理UI逻辑;Model 就作为系统中的对象,包含数据对象。

一个 View 对应一个 ViewModel ,一个 ViewModel 可以聚合多个 Model,ViewModel 可以对应多个 View,在 MVVM 下,所有事件和动作都转换成命令,如按钮的点击操作,不在是触发点击事件,而是绑定到命令,由命令去执行对应的逻辑。

MVVM 模式的优势包括:

分离关注点:MVVM 将用户界面逻辑和业务逻辑彻底分开,使代码结构更清晰,易于理解和维护。

可测试性:由于 View 和 ViewModel 之间的解耦,可以更轻松地对 ViewModel 进行单元测试,而无需涉及到用户界面的操作。

可扩展性:MVVM 支持模块化开发,不同的 View 和 ViewModel 可以独立开发和组合,使应用程序更易于扩展。

可重用性:ViewModel 可以与不同的 View进行重用,从而减少了重复编写代码的工作。

2. 实现简单MVVM

2.1. Part 1

xml 复制代码
<Window x:Class="WpfApp1.MainWindow"

        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:sys="clr-namespace:System;assembly=mscorlib"
        xmlns:local="clr-namespace:WpfApp1"
        Title="MVVM Demo" Height="450" Width="800">


    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition />
            <RowDefinition />
        </Grid.RowDefinitions>


        <StackPanel HorizontalAlignment="Center" VerticalAlignment="Center" 
                    DataContext="{x:Static sys:DateTime.Now}">
            <TextBlock Text="{Binding Year, StringFormat='The year is {0}'}" />
            <TextBlock Text="{Binding StringFormat='The month is {0:MMMM}'}" />
            <TextBlock Text="{Binding Day, StringFormat='The day is {0}'}" />
            <TextBlock Text="{Binding StringFormat='The time is {0:T}'}" />
        </StackPanel>
    </Grid>
</Window>

这段 Xaml 在 StackPanel 的 DataContext 中设置了一个绑定到当前日期和时间的 DateTime 对象,然后通过数据绑定将 DateTime 对象的各个属性显示在不同的子元素 TextBlock 中,同时对显示内容进行了格式化。

运行程序,文本中的日期和时间只会在构造和初始化的时候设置一次,不会随时间的变化而变化。

2.2. Part 2

上面的页面写出来显然是没有意义的,我们想让它实时显示当前时间,这就需要有个东西在时间发生变化时一直更新页面上的时间,这个过程一般会通过后台代码完成,当然可以通过一个 Timer 搞定,但就和这篇文章的内容没关系了,用 MVVM 的模式怎么实现呢?

首先从 MVVM 三部分来看,View 就是标题为MVVM Demo的窗体,Model 是 DateTime 对象,需要 ViewModel 来处理时间数据同时通知页面响应更改。

创建一个ClockViewModel.cs类:

csharp 复制代码
 public class ClockViewModel : INotifyPropertyChanged
 {
     public event PropertyChangedEventHandler PropertyChanged;


     private DateTime _dateTime;
     private Timer _timer;


     public DateTime DateTime
     {
         get => _dateTime;
         set
         {
             if (_dateTime != value)
             {
                 _dateTime = value;
                 OnPropertyChanged();
             }
         }
     }


     public ClockViewModel()
     {
         DateTime = DateTime.Now;
         _timer = new Timer(new TimerCallback((s) => DateTime = DateTime.Now),
                            null, TimeSpan.Zero, TimeSpan.FromSeconds(1));
     }


     ~ClockViewModel() =>
         _timer.Dispose();


     public void OnPropertyChanged([CallerMemberName] string name = "")
     {
         PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
     }
 }

ClockViewModel 类实现了 INotifyPropertyChanged 接口,并通过 Timer 定时更新时间并触发属性更改通知,提供实时的系统时间。完成 ViewModel 部分以后,将 ViewModel 绑定到视图 View - MainWindow 上:

xml 复制代码
<Window x:Class="WpfApp1.MainWindow"

        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:sys="clr-namespace:System;assembly=mscorlib"
        xmlns:local="clr-namespace:WpfApp1"
        Title="MVVM Demo" Height="450" Width="800">


    <Window.DataContext>
        <local:ClockViewModel />
    </Window.DataContext>


    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition />
            <RowDefinition />
        </Grid.RowDefinitions>


        <StackPanel HorizontalAlignment="Center" VerticalAlignment="Center" 
                    DataContext="{x:Static sys:DateTime.Now}">
            <TextBlock Text="{Binding Year, StringFormat='The year is {0}'}" />
            <TextBlock Text="{Binding StringFormat='The month is {0:MMMM}'}" />
            <TextBlock Text="{Binding Day, StringFormat='The day is {0}'}" />
            <TextBlock Text="{Binding StringFormat='The time is {0:T}'}" />
        </StackPanel>


        <StackPanel Grid.Row="1" HorizontalAlignment="Center" VerticalAlignment="Center">
            <TextBlock Text="{Binding DateTime, StringFormat='The time is {0:T}'}" />
        </StackPanel>
    </Grid>
</Window>

这样就可以得到一个 MVVM 模式下的时钟了:

相关推荐
huizhixue-IT6 小时前
华为存储考试内容&HCIP-Storage
wpf
桂月二二1 天前
实时事件流处理架构的容错设计
架构·wpf
源之缘-OFD先行者1 天前
GMap.NET + WPF:构建高性能 ADS-B 航空器追踪平台
.net·wpf·ads-b
Marzlam1 天前
WPF学习路线
wpf
weixin_535455791 天前
WPF设计学习记录滴滴滴2
学习·wpf
^@^lemon tea^@^1 天前
WPF 浅述IsHitTestVisible属性
wpf·wpf 穿透
lixy5791 天前
C# WPF 命令机制(关闭CanExecute自动触发,改手动)
c#·wpf
Marzlam2 天前
一文了解WPF技术简介
wpf
arriettyandray2 天前
C#/WPF学习系列之问题记录——使用不流畅
c#·wpf
勘察加熊人2 天前
wpf+c#路径迷宫鼠标绘制
开发语言·c#·wpf