最近. NET 8 的 WPF 推出了 WPF File Dialog改进,这样无需再引用 Win32 命名空间就可以实现文件夹的选择与存储了,算是一个很方便的改进了。顺手写了一个小的 WPF 程序,在使用 Model-View-ViewModel(MVVM) 模式的时候,我不想使用 Prism 等重量级的框架,找了一个轻量级的 MVVM Community Toolkit (以下简称 MVVM Toolkit)。

在现代 WPF 应用程序开发中,遵循 MVVM(Model-View-ViewModel)模式已成为一种标准做法。MVVM 模式视图和逻辑分离,提高了代码的可测试性、可维护性。

MVVM Toolkit 核心功能

MVVM Toolkit 提供了一系列的功能,使得在 WPF 等程序中实现 MVVM 更加简单。

  1. ViewModel 基类:基类(例如 ObservableObject)为实现属性更改通知提供了基础结构,简化了 ViewModel 的创建过程。
  2. 命令的实现:MVVM Toolkit 提供了易于使用的命令实现(RelayCommand ),允许 View 以声明方式绑定到 ViewModel 上的方法。
  3. 弱消息机制:弱消息机制(WeakReferenceMessenger)允许不同对象之间收发消息,而不会造成内存泄漏。

安装

使用 nuget 安装到 WPF 项目中即可。由于 MVVM Toolkit 面向. NET Standard,所以可在任何应用平台上使用:UWP、WinForms、WPF、Xamarin、Uno 等。

Install-Package CommunityToolkit.Mvvm

代码生成

在 MVVM Toolkit 中,代码生成器扮演着重要的角色。通过利用代码生成器,它能够自动化诸如属性更改通知和命令实现等常见任务,减少样板代码,提高开发效率。

例如,开发者可以通过简单的属性标记,自动实现 INotifyPropertyChanged 接口:

partial class MyViewModel : ObservableObject
{
[ObservableProperty]
private string name; [ObservableProperty]
private bool isEnabled;
}

以上代码会通过 Roslyn 的代码生成器功能生成如下代码:

 partial class MyViewModel
{
public string Name
{
get => name;
set => SetProperty(ref name, value);
} public bool IsEnabled
{
get => isEnabled;
set => SetProperty(ref isEnabled, value);
}
}

在没有 MVVM Toolkit 的情况下,开发者需要手动实现 MVVM 的各个部分。例如,实现 INotifyPropertyChanged 接口通常涉及创建大量样板代码:

public class MyViewModel : INotifyPropertyChanged
{
private string myProperty; public string MyProperty
{
get => myProperty;
set
{
myProperty = value;
OnPropertyChanged(nameof(MyProperty));
}
} public event PropertyChangedEventHandler PropertyChanged; protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}

相比之下,MVVM Toolkit 不仅减少了需要编写的代码量,也降低了出错的可能性,使得开发更加专注于业务逻辑本身。

使用 MVVM Toolkit 创建 ViewModel

依赖属性与命令

以下是使用 MVVM Toolkit 创建 ViewModel 的一个简单示例:

public partial class MainViewModel : ObservableObject
{
[ObservableProperty]
private string title = "Hello, MVVM Toolkit!"; [RelayCommand]
private void DealWithData()
{
// 数据处理逻辑
}
}

ObservablePropertyRelayCommand 属性标记自动处理了属性更改通知和命令实现的细节,开发者只需关注业务逻辑,并在 XAML 中绑定对应的属性/命令,组件会自动生成对应的依赖属性。

注意,请一定使用 camelCase 命名法(可以带前导_),代码生成器会生成符合 PascalCase 标准的属性/方法名称。

弱引用消息

再看 WeakReferenceMessenger 在不同 ViewModel 或组件间发送和接收消息:

1. 定义消息类型

首先定义一个消息类型。消息可以是任何类或结构,通常包含发送者想要传递的数据:

public class MyMessage
{
public string Text { get; } public MyMessage(string text)
{
Text = text;
}
}

2. 发送消息

在一个 ViewModel 或组件中,你可以发送消息。假设有一个 SenderViewModel

public class SenderViewModel
{
private void SendMessage()
{
var message = new MyMessage("Hello from SenderViewModel");
WeakReferenceMessenger.Default.Send(message);
}
}

SendMessage 方法创建了一个 MyMessage 实例,并通过 WeakReferenceMessenger.Default.Send 方法发送。

3. 接收消息

在另一个 ViewModel 或组件中,你可以注册以接收特定类型的消息。例如,你可能有一个 ReceiverViewModel

public class ReceiverViewModel
{
public ReceiverViewModel()
{
// 注册以接收 MyMessage 类型的消息
WeakReferenceMessenger.Default.Register<MyMessage>(this, (recipient, message) =>
{
// 处理接收到的消息
string receivedText = message.Text;
// Do something with receivedText
});
}
}

ReceiverViewModel 的构造函数中,使用 WeakReferenceMessenger.Default.Register 方法注册了消息接收器,当发送方发送 MyMessage 类型的消息时,这个接收器将被调用。

4. 解除消息注册

在不再需要接收消息时,或者在对象被销毁之前,应该解除消息的注册,以避免内存泄漏:

public class ReceiverViewModel
{
public ReceiverViewModel()
{
WeakReferenceMessenger.Default.Register<MyMessage>(this, OnMessageReceived);
} private void OnMessageReceived(object recipient, MyMessage message)
{
// 处理消息
} ~ReceiverViewModel()
{
WeakReferenceMessenger.Default.Unregister<MyMessage>(this);
}
}

ReceiverViewModel 通过其析构函数取消注册(也可以使用 IDispose 实现),确保当 ViewModel 被回收时,不会有消息处理器的引用残留。

总结

MVVM Toolkit 为 WPF 开发者提供了一个强大且易用的工具,它极大地简化了 MVVM 模式实现过程,虽然其他框架(MVVM Light/Prism 等)也提供了类似功能,但它非常轻量,使用简单,非常适合小型工程使用。

本文使用 AI 帮助润色了部分内容,文章经过人工校对。

使用MVVM Toolkit简化WPF开发的更多相关文章

  1. 简化MVVM属性设置和修改 - .NET CORE(C#) WPF开发

    微信公众号:Dotnet9,网站:Dotnet9,问题或建议:请网站留言, 如果对您有所帮助:欢迎赞赏. 简化MVVM属性设置和修改 - .NET CORE(C#) WPF开发 阅读导航 常用类属性设 ...

  2. Mvvm Light Toolkit for WPF/Silverlight系列之搭建mvvmlight开发框架

    Mvvm Light Toolkit for WPF/Silverlight系列之搭建mvvmlight开发框架   本章节,我将通过示例介绍如何搭建mvvmlight开发环境.示例中的我会针对wpf ...

  3. MvvmLight学习篇—— Mvvm Light Toolkit for wpf/silverlight系列(导航)

    系列一:看的迷迷糊糊的 一.Mvvm Light Toolkit for wpf/silverlight系列之准备工作 二.Mvvm Light Toolkit for wpf/silverlight ...

  4. 【WPF开发备忘】使用MVVM模式开发中列表控件内的按钮事件无法触发解决方法

    实际使用MVVM进行WPF开发的时候,可能会用到列表控件中每行一个编辑或删除按钮,这时直接去绑定,发现无法响应: <DataGridTemplateColumn Header="操作& ...

  5. [WPF] 使用 MVVM Toolkit 构建 MVVM 程序

    1. 什么是 MVVM Toolkit 模型-视图-视图模型 (MVVM) 是用于解耦 UI 代码和非 UI 代码的 UI 体系结构设计模式. 借助 MVVM,可以在 XAML 中以声明方式定义 UI ...

  6. 使用MVVM设计模式构建WPF应用程序

    使用MVVM设计模式构建WPF应用程序 本文是翻译大牛Josh Smith的文章,WPF Apps With The Model-View-ViewModel Design Pattern,译者水平有 ...

  7. Prism+MaterialDesign+EntityFramework Core+Postgresql WPF开发总结 之 基础篇

    本着每天记录一点成长一点的原则,打算将目前完成的一个WPF项目相关的技术分享出来,供团队学习与总结. 总共分三个部分: 基础篇主要争对C#初学者,巩固C#常用知识点: 中级篇主要争对WPF布局与美化, ...

  8. 使用 MVVM Toolkit Source Generators

    关于 MVVM Toolkit 最近 .NET Community Toolkit 发布了 8.0.0 preview1,它包含了从 Windows Community Toolkit 迁移过来的以下 ...

  9. 领域驱动和MVVM应用于UWP开发的一些思考

    领域驱动和MVVM应用于UWP开发的一些思考 0x00 起因 有段时间没写博客了,其实最近本来是根据梳理的MSDN上的资料(UWP开发目录整理)有条不紊的进行UWP学习的.学习中有了心得体会或遇到了问 ...

  10. MVVM框架从WPF移植到UWP遇到的问题和解决方法

    MVVM框架从WPF移植到UWP遇到的问题和解决方法 0x00 起因 这几天开始学习UWP了,之前有WPF经验,所以总体感觉还可以,看了一些基础概念和主题,写了几个测试程序,突然想起来了前一段时间在W ...

随机推荐

  1. phpexcel图片获取

    phpexcel图片获取常见的两种方式: require_once dirname(__FILE__) . '/../Jn/PHPExcel.php'; $filePath = "123.x ...

  2. 何时使用MongoDB而不是MySql

    什么是 MySQL 和 MongoDB MySQL 和 MongoDB 是两个可用于存储和管理数据的数据库管理系统.MySQL 是一个关系数据库系统,以结构化表格格式存储数据.相比之下,MongoDB ...

  3. Mybatis框架的搭建和基本使用

    本文总结最原始Mybatis框架的搭建和最基本使用(不涉及Spring框架体系). 1 依赖 首先,我们要引入Mybatis依赖: <dependency> <groupId> ...

  4. Java 配置 HTTP/Socks 代理竟能如此简单

    在网络请求过程中,使用代理是一种常见的需求.代理服务器可以帮助我们隐藏真实的 IP 地址.加速访问速度.访问公司特定内网等等要求.在 Java 中,我们可以通过一些库或框架来实现代理的设置和使用. 但 ...

  5. 【RocketMQ】消息的拉取总结

    在上一讲中,介绍了消息的存储,生产者向Broker发送消息之后,数据会写入到CommitLog中,这一讲,就来看一下消费者是如何从Broker拉取消息的. RocketMQ消息的消费以组为单位,有两种 ...

  6. CVE-2018-8120 漏洞复现

    CVE-2018-8120 漏洞复现 漏洞描述 win32k.sys中函数 SetImeInfoEx未对指针进行合法性检查,从而导致一个任意地址写. 漏洞分析 漏洞成因 int __stdcall S ...

  7. RK3568开发笔记(十):开发板buildroot固件移植开发的应用Demo,启动全屏显示

    前言   上一篇,移植应用前的通讯接口工作和全屏工作都已经完成了.本篇移植开发的商业应用.   交叉编译好应用   (略),参照<RK3568开发笔记(八):开发板烧写buildroot固件(支 ...

  8. Spring Cache + Caffeine实现本地缓存

    Caffeine简介 Caffeine是一个高性能,高命中率,低内存占用,near optimal 的本地缓存,简单来说它是 Guava Cache 的优化加强版 依赖 <dependency& ...

  9. Spring扩展接口(1):ApplicationContextInitializer

    在此系列文章中,我总结了Spring扩展接口,以及各个扩展点的使用场景.并整理出一个bean在spring中从被加载到初始化到销毁的所有可扩展点的顺序调用图.这样,我们也可以看到bean是如何一步步加 ...

  10. 在线问诊 Python、FastAPI、Neo4j — 生成 Cypher 语句

    目录 构建节点字典 构建Cypher CQL语句 Test 这边只是为了测试,演示效果和思路,实际应用中,可以通过NLP构建CQL 接上一篇的问题分类 question = "请问最近看东西 ...