C# WPF入门学习主线篇(三十)—— MVVM(Model-View-ViewModel)模式

C# WPF入门学习主线篇(三十)------ MVVM(Model-View-ViewModel)模式

MVVM(Model-View-ViewModel)模式是WPF(Windows Presentation Foundation)开发中的一种常用架构模式。它通过将用户界面(View)与业务逻辑和数据(Model)分离开来,提高了代码的可维护性和可测试性。本文将详细介绍MVVM模式的基本概念和实现方法,并通过一个示例演示如何在WPF应用程序中使用MVVM模式。

一、MVVM模式的基本概念

1. Model

Model表示应用程序的核心数据和业务逻辑。它通常包含数据结构、业务规则和数据访问代码。在MVVM模式中,Model不依赖于UI,它是独立的可重用组件。

2. View

View表示用户界面,它负责显示数据和接收用户输入。View通过数据绑定和命令与ViewModel交互,而不直接访问Model。View通常是XAML文件及其相关的代码隐藏文件。

3. ViewModel

ViewModel是View和Model之间的桥梁。它负责从Model获取数据,并将这些数据提供给View,同时处理用户在View上的交互。ViewModel通常实现通知机制(如INotifyPropertyChanged接口),以便在数据变化时通知View进行更新。

二、MVVM模式的实现

接下来,我们通过一个简单的示例演示如何在WPF应用程序中实现MVVM模式。

1. 定义Model

首先,我们定义一个简单的Model类Person,包含两个属性NameAge

csharp 复制代码
public class Person
{
    public string Name { get; set; }
    public int Age { get; set; }
}

2. 定义ViewModel

接下来,我们定义ViewModel类PersonViewModel,实现INotifyPropertyChanged接口,以便在属性变化时通知View。

csharp 复制代码
using System.ComponentModel;

public class PersonViewModel : INotifyPropertyChanged
{
    private Person _person;

    public PersonViewModel()
    {
        _person = new Person { Name = "John Doe", Age = 30 };
    }

    public string Name
    {
        get => _person.Name;
        set
        {
            if (_person.Name != value)
            {
                _person.Name = value;
                OnPropertyChanged("Name");
            }
        }
    }

    public int Age
    {
        get => _person.Age;
        set
        {
            if (_person.Age != value)
            {
                _person.Age = value;
                OnPropertyChanged("Age");
            }
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    protected void OnPropertyChanged(string propertyName)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

3. 定义View

然后,我们定义View,使用XAML文件和数据绑定将UI控件绑定到ViewModel的属性。

xml 复制代码
<Window x:Class="WpfApp.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MVVM Demo" Height="200" Width="300">
    <Grid>
        <StackPanel>
            <TextBox Text="{Binding Name, UpdateSourceTrigger=PropertyChanged}" FontSize="16" Margin="10"/>
            <TextBox Text="{Binding Age, UpdateSourceTrigger=PropertyChanged}" FontSize="16" Margin="10"/>
        </StackPanel>
    </Grid>
</Window>

4. 在MainWindow中绑定ViewModel

最后,我们在MainWindow的构造函数中创建PersonViewModel实例,并将其设置为DataContext。

csharp 复制代码
using System.Windows;

namespace WpfApp
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            this.DataContext = new PersonViewModel();
        }
    }
}

三、实现命令绑定

在MVVM模式中,我们通常使用命令来处理用户的交互,而不是直接在View中处理事件。下面我们演示如何在ViewModel中实现命令绑定。

1. 定义RelayCommand类

我们定义一个通用的命令类RelayCommand,实现ICommand接口。

csharp 复制代码
using System;
using System.Windows.Input;

public class RelayCommand : ICommand
{
    private readonly Action<object> _execute;
    private readonly Func<object, bool> _canExecute;

    public RelayCommand(Action<object> execute, Func<object, bool> canExecute = null)
    {
        _execute = execute;
        _canExecute = canExecute;
    }

    public bool CanExecute(object parameter) => _canExecute == null || _canExecute(parameter);

    public void Execute(object parameter) => _execute(parameter);

    public event EventHandler CanExecuteChanged
    {
        add => CommandManager.RequerySuggested += value;
        remove => CommandManager.RequerySuggested -= value;
    }
}

2. 在ViewModel中定义命令

在ViewModel中定义命令并实现命令的逻辑。

csharp 复制代码
public class PersonViewModel : INotifyPropertyChanged
{
    private Person _person;

    public PersonViewModel()
    {
        _person = new Person { Name = "John Doe", Age = 30 };
        UpdateCommand = new RelayCommand(UpdatePerson);
    }

    public string Name
    {
        get => _person.Name;
        set
        {
            if (_person.Name != value)
            {
                _person.Name = value;
                OnPropertyChanged("Name");
            }
        }
    }

    public int Age
    {
        get => _person.Age;
        set
        {
            if (_person.Age != value)
            {
                _person.Age = value;
                OnPropertyChanged("Age");
            }
        }
    }

    public ICommand UpdateCommand { get; }

    private void UpdatePerson(object parameter)
    {
        Name = "Updated Name";
        Age = 35;
    }

    public event PropertyChangedEventHandler PropertyChanged;

    protected void OnPropertyChanged(string propertyName)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

3. 在View中绑定命令

在View中添加一个按钮,并将其命令属性绑定到ViewModel中的命令。

xml 复制代码
<Window x:Class="WpfApp.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MVVM Demo" Height="200" Width="300">
    <Grid>
        <StackPanel>
            <TextBox Text="{Binding Name, UpdateSourceTrigger=PropertyChanged}" FontSize="16" Margin="10"/>
            <TextBox Text="{Binding Age, UpdateSourceTrigger=PropertyChanged}" FontSize="16" Margin="10"/>
            <Button Content="Update" Command="{Binding UpdateCommand}" FontSize="16" Margin="10"/>
        </StackPanel>
    </Grid>
</Window>

四、总结

在本篇文章中,我们介绍了MVVM模式的基本概念,并通过一个简单的示例演示了如何在WPF应用程序中实现MVVM模式。我们详细讲解了Model、View和ViewModel的定义和实现,以及如何通过数据绑定和命令绑定实现UI和业务逻辑的分离。

通过MVVM模式,我们可以将业务逻辑和数据与UI分离,从而提高代码的可维护性、可测试性和可重用性。希望本文能帮助你更好地理解和应用MVVM模式,提高WPF开发的效率和质量。

相关推荐
Nu11PointerException2 小时前
JAVA笔记 | ResponseBodyEmitter等异步流式接口快速学习
笔记·学习
@小博的博客5 小时前
C++初阶学习第十弹——深入讲解vector的迭代器失效
数据结构·c++·学习
南宫生6 小时前
贪心算法习题其四【力扣】【算法学习day.21】
学习·算法·leetcode·链表·贪心算法
懒惰才能让科技进步7 小时前
从零学习大模型(十二)-----基于梯度的重要性剪枝(Gradient-based Pruning)
人工智能·深度学习·学习·算法·chatgpt·transformer·剪枝
love_and_hope7 小时前
Pytorch学习--神经网络--搭建小实战(手撕CIFAR 10 model structure)和 Sequential 的使用
人工智能·pytorch·python·深度学习·学习
Chef_Chen7 小时前
从0开始学习机器学习--Day14--如何优化神经网络的代价函数
神经网络·学习·机器学习
小码编匠7 小时前
一款 C# 编写的神经网络计算图框架
后端·神经网络·c#
芊寻(嵌入式)7 小时前
C转C++学习笔记--基础知识摘录总结
开发语言·c++·笔记·学习
hong1616888 小时前
跨模态对齐与跨领域学习
学习