WPF插件之 - PropertyChanged.Fody插件的使用详解

news2025/1/11 10:16:40

总目录


文章目录

  • 总目录
  • 一、PropertyChanged.Fody是什么?
  • 二、PropertyChanged.Fody的安装
  • 三、PropertyChanged.Fody的功能
    • 1. 特性
      • 1 实现属性通知的功能
      • 2 通知其他属性
      • 4 不进行属性通知
      • 3 指定属性更改时将调用的方法
      • 5 设置当前属性依赖的属性
      • 6 不检查是否相等
      • 7 DoNotSetChangedAttribute
    • 2. 配置FodyWeavers.xml文件
      • 1 EventInvokerNames
      • 2 InjectOnPropertyNameChanged
      • 3 CheckForEquality
  • 结语


一、PropertyChanged.Fody是什么?

  • PropertyChanged.Fody 主要是实现了INotifyPropertyChanged 接口的,然后通过特性对外提供相关属性通知功能。
  • 引用该插件能够使我们属性通知的代码更为简洁。
  • 源码:https://github.com/Fody/PropertyChanged

如在阅读本文后,后续遇到文中没有提及的问题或知识点,可以查看源码说明文档

二、PropertyChanged.Fody的安装

1.首先添加PropertyChanged.Fody的Nuget程序包

在这里插入图片描述
如果通过程序包管理器控制台安装,则如下操作

  • 先调出控制台,然后根据需求修改程序包源和需要安装程序包的项目
    在这里插入图片描述
  • 输入程序包的安装命令,即可完成程序包的安装
PM> Install-Package Fody
PM> Install-Package PropertyChanged.Fody

2.再者添加FodyWeavers.xml 文件

一般安装完PropertyChanged.Fody程序包后,会自动创建FodyWeavers.xml 文件;如果没有自动创建FodyWeavers.xml 文件,此时我们可以重新生成项目,然后项目生成时会自动在项目根目录下创建FodyWeavers.xml 文件,此时还没有包括在项目中,我们需要先显示所有文件,然后将FodyWeavers.xml 文件包含在项目中即可。如果以上操作均没有生成FodyWeavers.xml 文件,则自行在项目中创建FodyWeavers.xml 文件,然后在文件中,配置如下代码:

<Weavers>
  <PropertyChanged/>
</Weavers>

三、PropertyChanged.Fody的功能

当我们安装完程序包后,下面就是主要介绍如何使用该程序包中提供的功能。

1. 特性

PropertyChanged.Fody的核心功能就是提供了一系列的特性供我们使用,通过给属性和类标注特性,是我们的代码更加的简洁

1 实现属性通知的功能

通常我们自己手动实现INotifyPropertyChanged接口后,会需要将我们自己的ViewModel继承自实现类,然后在属性中调用方法来实现属性通知。如下示例中,ViewModelBase为自行实现INotifyPropertyChanged接口的实现类:

    public class MainViewModel:ViewModelBase
    {
        private double _num;
        public double Num
        {
            get { return _num; }
            set { _num = value; OnPropertyChanged(); }
        }
    }

当我们使用了PropertyChanged.Fody插件后,可通过以下方式来实现一样的功能

  • 方式1:直接将ViewModel的类继承自INotifyPropertyChanged类,所有实现INotifyPropertyChanged的类都将向属性设置器注入通知代码
  • 方式2:在ViewModel的类上添加AddINotifyPropertyChangedInterface特性,旧版是添加ImplementPropertyChanged 特性,但该特性已弃用

方式1 示例代码:

    public class MainViewModel : INotifyPropertyChanged
    {
        public double Num { get; set; }

        public event PropertyChangedEventHandler PropertyChanged;
    }

方式2示例代码:

    [AddINotifyPropertyChangedInterface]
    public class MainViewModel
    {
        public double Num { get; set; }
    }

以上两种方式作用是一样的,都可以实现属性通知,并且还可以使我们属性通知的代码量大大的减少,编码界面更为简洁清晰。

通过下图了解一下通过以上方式,实现属性通知后的反编译代码
在这里插入图片描述

下面我们通过一个完整的案例了解一下具体的使用,案例中实现Num1+Num2=Total:
在这里插入图片描述

在这里插入图片描述
反编译后的代码:
在这里插入图片描述
通过以上案例我们知道:

  • 当我们在添加AddINotifyPropertyChangedInterface特性的类中,A属性引用了B和C属性,那么B和C属性代码中就会插入通知A属性更新的代码;如上面的案例中,Total属性中引用了Num1和Num2,反编译后Num1和Num2的属性访问器中就会添加<>OnPropertyChanged(<>PropertyChangedEventArgs.Total); 这样的一句代码,表示Num1和Num2属性更新后,不仅会通知自身,还会通知Total。
  • 当属性中有了业务逻辑代码,则不会插入属性更新的代码,如上案例Total属性的get访问器中有了业务代码,那么Total将不具有属性更新通知的功能

注意:只有在类上标注AddINotifyPropertyChangedInterface特性或者实现INotifyPropertyChanged接口后,实现PropertyChanged.Fody中其他的特性才能生效,否则单独使用是无效的。

2 通知其他属性

通过AlsoNotifyFor特性,我们可以实现在通知自身属性的时候,通知其他的属性进行更新;
实现原理:也仅仅是使用了该特性后,set访问器中会自动插入对应属性的属性通知代码

通过下图的源代码和反编译代码对比图可以加以佐证,在这里插入图片描述
另外建议使用nameof去配置需要 另外通知的属性名,不容易出现低级错误;再者可以通过逗号配置多个需要另外通知的属性。

    [AddINotifyPropertyChangedInterface]
    public class MainViewModel
    {
        [AlsoNotifyFor(nameof(Total),nameof(Num2))]
        public double Num1 { get; set; }
        public double Num2 { get; set; }
        public double Total { get; set; }
    }

4 不进行属性通知

如果ViewModel中的某一些属性,我们并不希望其具有属性通知的功能,可以使用DoNotNotify特性。
在这里插入图片描述

    [AddINotifyPropertyChangedInterface]
    public class MainViewModel
    {
        [DoNotNotify]
        public double Num1 { get; set; }
        public double Num2 { get; set; }
        public double Total { get; set; }
    }

3 指定属性更改时将调用的方法

默认情况下:如果有一个属性为Num,有一个方法为 OnNumChanged方法,那么在Num属性值更新的时候,就会执行OnNumChanged方法,只要是方法符合以上命名规则,就会自动生成调用代码。
在这里插入图片描述

    [AddINotifyPropertyChangedInterface]
    public class MainViewModel
    {
    	//在Num1更新时,自动调用OnNum1Changed方法
        public double Num1 { get; set; }
        public double Num2 { get; set; }

        public double Total { get; set; }

        private void OnNum1Changed()
        {
            Total = Num1 + Num2;
        }
    }

但是,如果我们向明确的指定属性更改时需要调用的方法,则需通过OnChangedMethod特性。

通过下图了解OnChangedMethod特性的原理,原理很简单就是在set访问器中调用特性中配置的方法。
在这里插入图片描述

    [AddINotifyPropertyChangedInterface]
    public class MainViewModel
    {
        [OnChangedMethod(nameof(OnNumChanged))]
        public double Num1 { get; set; }

        [OnChangedMethod(nameof(OnNumChanged))]
        public double Num2 { get; set; }
        public double Total { get; set; }

        private void OnNumChanged()
        {
            Total = Num1 + Num2;
        }
    }

以上案例表示当Num1和Num2 更新的时候,就执行OnNumChanged这个方法计算数字和。

5 设置当前属性依赖的属性

我们知道当我们给属性添加了AlsoNotifyFor特性的时候,可以实现在通知自身属性的时候,通知其他的属性进行更新;但是如果多个属性都通过AlsoNotifyFor指向的是同一个属性的时候,逐个添加不免有些麻烦;此时我们就可以使用DependsOn 特性,统一在最终指向的属性上,设置其依赖的属性即可。

在这里插入图片描述

    [AddINotifyPropertyChangedInterface]
    public class MainViewModel
    {
        public double Num1 { get; set; }
        public double Num2 { get; set; }

        [DependsOn(nameof(Num1),nameof(Num2))]
        public double Total { get; set; }
    }

6 不检查是否相等

默认情况下,所有属性通知中都会检查属性值是否相等,如果属性值相等,则不会进行通知;原理代码如下:

public string Property1
{
    get
    {
        return property1;
    }
    set
    {
        if (!String.Equals(property1, value))
        {
            property1 = value;
            OnPropertyChanged("Property1");
        }
    }
}

但在某些情况下,我们需要无论是否相等都会进行通知,这个时候,可以在属性上标记DoNotCheckEquality特性以跳过是否相等的检查。
在这里插入图片描述

    [AddINotifyPropertyChangedInterface]
    public class MainViewModel
    {
        [DoNotCheckEquality]
        public double Num1 { get; set; }
        public double Num2 { get; set; }
        public double Total { get; set; }

    }

当我们给属性加上DoNotCheckEquality特性的时候,就相当于给去掉了Object.Equals() 这个判断。

7 DoNotSetChangedAttribute

如果在添加了AddINotifyPropertyChangedInterface特性或者实现INotifyPropertyChanged接口的实现类中,有一个属性是IsChanged属性,那么默认情况下,当前类中的所有属性只要发生变化,都会将IsChanged 的属性值设置为True;

public bool IsChanged { get; set; }

如果希望在某个属性变化时,不设置IsChanged的属性值,可以给属性添加DoNotSetChanged特性,如下所示:

    [AddINotifyPropertyChangedInterface]
    public class MainViewModel
    {
        public bool IsChanged { get; set; }
        public double Num1 { get; set; }
        public double Num2 { get; set; }

        [DoNotSetChanged]
        public double Total { get; set; }
    }

在这里插入图片描述

2. 配置FodyWeavers.xml文件

1 EventInvokerNames

该配置用于更改激发属性通知事件的方法名称,这是一个以逗号分隔形式接受多个值的字符串。默认值为:

<?xml version="1.0" encoding="utf-8" ?>
<Weavers>
  <PropertyChanged EventInvokerNames="OnPropertyChanged, NotifyOfPropertyChange, RaisePropertyChanged, NotifyPropertyChanged, NotifyChanged"/>
</Weavers>

默认值覆盖了WPF中大多数的MVVM框架对于激发通知事件的方法命名,如Prism和MVVMLight 框架中使用的是RaisePropertyChanged,Caliburn Micro中使用的是NotifyOfPropertyChange。

如果需要指定激发属性通知事件方法的名称,则如下指定即可。基本是作此配置的,因为默认值已经覆盖大多数的框架。

<?xml version="1.0" encoding="utf-8" ?>
<Weavers>
  <PropertyChanged EventInvokerNames="NotifyPropertyChanged"/>
</Weavers>

2 InjectOnPropertyNameChanged

用于控制是否启用On_PropertyName_Changed功能。默认值为true,启用该功能。

On_PropertyName_Changed 的功能就是:属性更改时执行对应名称的方法(如Num对应的OnNumChanged)以及OnChangedMethod特性所实现的功能

<?xml version="1.0" encoding="utf-8" ?>
<Weavers>
  <PropertyChanged InjectOnPropertyNameChanged='false'/>
</Weavers>

3 CheckForEquality

用于控制是否应创建相等检查。如果为false,将对项目禁用相等检查。默认值为true,创建相等检查

<?xml version="1.0" encoding="utf-8" ?>
<Weavers>
  <PropertyChanged CheckForEquality='false'/>
</Weavers>

结语

以上就是本文的内容,希望以上内容可以帮助到您,如文中有不对之处,还请批评指正。

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

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

相关文章

lua:浅谈对元表和元方法的认识

前言 本篇在讲什么 浅谈对Lua元表和元方法的理解 本篇适合什么 适合初学Lua的小白 本篇需要什么 对Lua语法有简单认知 依赖Lua5.1的环境 依赖Sublime Text3编辑器 本篇的特色 具有全流程的图文教学 重实践&#xff0c;轻理论&#xff0c;快速上手 提供全流程的源码…

ETCD实现分布式锁

分布式锁具备特点 互斥性&#xff1a;在同一时刻&#xff0c;只有一个客户端能持有锁 安全性&#xff1a;避免死锁&#xff0c;如果某个客户端获得锁之后处理时间超过最大约定时间&#xff0c;或者持锁期间发生了故障导致无法主动释放锁&#xff0c;其持有的锁也能够被其他机制…

ANR实战案例 - FCM拉活启动优化

系列文章目录 提示&#xff1a;这里可以添加系列文章的所有文章的目录&#xff0c;目录需要自己手动添加 例如&#xff1a;第一章 Python 机器学习入门之pandas的使用 文章目录 系列文章目录前言一、Trace日志分析二、业务分析1.Firebase源码分析2.Firebase官方查看官方文档Dem…

数据压缩新利器!小精灵ELF助你高效存储与传输

存储空间不够用&#xff1f;网络传输太慢&#xff1f;想必每个人在生活中都会遇到这些问题。看着爆满的硬盘、焦急的等待数据的接受&#xff0c;更新设备&#xff1f;不是每个人都能承担这个成本。那不如尝试一下无损压缩&#xff1f; 为了减少存储空间的占用&#xff0c;提高…

《Netty》从零开始学netty源码(五十七)之ServerBootstrap.bind()

目录 ServerBootstrap.bind()initAndRegister()init()register()doBind0() ServerBootstrap.bind() 在第一篇的HelloWorld中通过ServerBootstrap.bind()方法绑定端口号并最终启动Netty的服务&#xff0c;服务端的bind过程如下&#xff1a; 上面的代码主要分成两部分&#xff0…

【P20】JMeter XPath提取器(XPath Extractor)

文章目录 一、准备工作二、测试计划 一、准备工作 百度&#xff1a;https://www.w3school.com.cn/example/xmle/cd_catalog.xml 进入网页后&#xff0c;右键检查或按F12&#xff0c;打开调试工具 如图&#xff0c;使用XPath提取器&#xff08;XPath Extractor&#xff09;获取…

typescript学习笔记(下)

1、类型拓宽 所有通过 let 或 var 定义的变量、函数的形参、对象的非只读属性&#xff0c;如果满足指定了初始值且未显式添加类型注解的条件&#xff0c;那么它们推断出来的类型就是指定的初始值字面量类型拓宽后的类型&#xff0c;这就是字面量类型拓宽。 下面我们通过字符串…

数据结构-排序-(选择、堆排序、归并排序、基数排序)

目录 一、选择排序 二、堆排序 排序 效率分析 三、归并排序 排序 分析 四、基数排序 一、选择排序 思想&#xff1a;每趟在待排序元素中选取关键字最小的元素加入有序子列 不稳定性 空间复杂度&#xff1a;O(1) 时间复杂度&#xff1a; void swap(int &a,int &…

[Linux] 动态 / 静态库的生成与使用

文章目录 简要概念 静态库生成使用 动态库生成使用 简要概念 库一般分为两种&#xff1a; 静态库动态库 在 Linux 中&#xff1a; 如果是动态库&#xff0c;库文件是以 .so 作后缀的如果是静态库&#xff0c;库文件是以 .a 作后缀的 库文件的命名&#xff1a; libXXX.so …

RBTree

目录 红黑树的概念 红黑树性质 红黑树节点设计 红黑树的插入 红黑树的验证 红黑树和AVL树的比较 红黑树的概念 红黑树&#xff0c;是一种二叉搜索树&#xff0c;但在每个结点上增加一个存储位表示结点的颜色&#xff0c;可以是Red或 Black。 通过对任何一条从根到叶子的…

Point-SLAM: Dense Neural Point Cloud-based SLAM阅读记录

前言 只读了前半部分就感慨文章结构真的好清晰&#xff0c;从Introduction到related work完完全全都在体现它的motivation——他做了一件什么事情&#xff1f;以及为什么要这么做&#xff1f;解决了什么问题。 第一遍阅读 keywords: 以RGBD作为输入 使用点云表示场景的 dens…

【P21】JMeter XPath2 提取器(XPath2 Extractor)

文章目录 一、准备工作二、测试计划 一、准备工作 百度&#xff1a;https://www.w3school.com.cn/example/xmle/cd_catalog.xml 进入网页后&#xff0c;右键检查或按F12&#xff0c;打开调试工具 如图&#xff0c;使用XPath2 提取器&#xff08;XPath2 Extractor&#xff09;…

python 使用pandas或xlrd、xlwt实现对Excel的读取、添加、追加等一系列封装

不说了&#xff0c;又是造轮子的一天。在此我要严重批评CSDN或百度一堆浑水摸鱼的&#xff0c;某些人明明代码明显报错也来上传发博客&#xff0c;要么就是标题党&#xff0c;代码没报错但压根就不是实现那个功能的&#xff0c;简直是浪费时间。 废话不多说直接贴代码&#xff…

Linux—网络基础

目录 计算机网络背景 网络发展 认识 "协议" 网络协议初识 协议分层 OSI七层模型 TCP/IP五层(或四层)模型 网络传输基本流程 协议报头 局域网通信 网络传输流程图 局域网通信图 跨网络通信图 数据包封装和分用 网络中的地址管理 认识IP地址 认识MAC地址…

8款主流产品原型设计软件分享

在产品设计中&#xff0c;你知道如何选择合适的产品设计软件吗&#xff1f;每个产品设计软件的功能实际上是不同的&#xff0c;不同的产品设计软件应用领域是不同的。 只有深入了解每个产品设计软件的功能和主要适合该软件的行业&#xff0c;我们才能在设计相应的产品时找到合…

linux内核篇-进程及其调度

介绍一个程序从源文件到进程执行的过程 1、编译链接&#xff08;源文件到二进制文件&#xff09; Linux 下面二进制的程序也要有严格的格式&#xff0c;称为ELF&#xff08;Executeable and Linkable Format&#xff0c;可执行与可链接格式&#xff09; &#xff0c;这个格式可…

Simulink 和 Gazebo联合仿真控制机械臂【Matlab R2022a】

逛 B 站&#xff0c;偶然发现一个 up 主上传的视频&#xff0c;可以实现 Simulink 中搭建机器人的控制器设计&#xff0c;对运行在虚拟机中 Gazebo 中的机械臂进行控制&#xff0c;链接&#xff1a;三关节机械臂Gazebo-Simulink联合仿真&#xff0c;这让我很感兴趣&#xff0c;…

Web基础 ( 一 ) HTML

1.HTML <input /><input typebutton value按钮 />1.1.概念 1.1.1.HTML文件是什么 HTML表示超文本标记语言&#xff08;Hyper Text Markup Language&#xff09;, HTML文件是一个包含标记的文本文件, 必须有htm标记或者html扩展名。 可以通过浏览器(Browser)直接…

如何用自己公司的知识、流程等来训练Chat GPT?

在玩过 ChatGPT 并向它询问有关世界、金融和初创公司的一般问题后&#xff0c;我开始思考&#xff1a;“如果我可以用我自己的初创公司甚至大型公司的所有流程、知识和商业经验来训练 AI 模型会怎样&#xff1f;企业&#xff1f;” 使用您自己公司的知识、流程等培训 ChatGPT …

华为OD机试 - 计算网络信号、信号强度( Python)

题目描述 网络信号经过传递会逐层衰减,且遇到阻隔物无法直接穿透,在此情况下需要计算某个位置的网络信号值。 注意:网络信号可以绕过阻隔物。 array[m][n] 的二维数组代表网格地图, array[i][j] = 0代表i行j列是空旷位置; array[i][j] = x(x为正整数)代表i行j列是信号源,…