【WPF.NET开发】弱事件模式

本文内容

  1. 先决条件
  2. 为什么要实现弱事件模式?
  3. 应该由谁实现弱事件模式?
  4. 如何实现弱事件模式

在应用程序中,附加到事件源的处理程序可能不会与将处理程序附加到源的侦听器对象一同销毁。 这种情况下会导致内存泄漏。 Windows Presentation Foundation (WPF) 引入了可用于解决此问题的设计模式。 设计模式为特定事件提供专用的管理器类,并在该事件的侦听器上实现接口。 此设计模式称为弱事件模式。

1、先决条件

本文假定你对路由事件有基本的了解,并且已阅读
路由事件概述。 若要遵循本文中的示例,如果熟悉 Extensible Application Markup Language (XAML) 并知道如何编写 Windows Presentation Foundation (WPF) 应用程序,将会很有帮助。

2、为什么要实现弱事件模式?

对事件的侦听可能会导致内存泄漏。 侦听事件的常用技术是使用特定于语言的语法,将处理程序附加到源上的事件。 例如,C# 语句 source.SomeEvent += new SomeEventHandler(MyEventHandler) 或 VB 语句 AddHandler source.SomeEvent, AddressOf MyEventHandler。 然而,此技术可创建从事件源到事件侦听器的强引用。 除非显式注销事件处理程序,否则侦听器的对象生存期将受到源的对象生存期的影响。 在某些情况下,你可能希望通过其他因素(例如,当前是否属于应用程序的可视化树)控制侦听器的对象生存期。 每当源的对象生存期超出侦听器的有用对象生存期时,侦听器的存活时间比必要时间要长。 在这种情况下,未分配的内存相当于内存泄漏。

弱事件模式旨在解决内存泄漏问题。 当侦听器需要注册事件时,都可以使用弱事件模式,但侦听器并不明确知晓事件会在何时注销。 当源的对象生存期超过侦听器的有用对象生存期时,也可以使用弱事件模式。 在这种情况下,有用与否将由你来决定。 弱事件模式允许侦听器注册事件和接收事件,而不会以任何方式影响侦听器的对象生存期特征。 实际上,对源的隐式引用并不能确定侦听器是否有资格执行垃圾回收。 由于是弱引用,因而引用是对弱事件模式和相关 API 的命名。 侦听器可以被垃圾回收或以其他方式销毁,而源可以继续运行,无需保留针对现已销毁的对象的不可回收的处理程序引用。

3、应该由谁实现弱事件模式?

弱事件模式主要与控件作者相关。 控件作者主要负责控件行为和控件包含,以及控件对其所插入的应用程序的影响。 这包括控件对象生存期行为,特别是处理所述的内存泄漏问题。

某些方案本身就适合应用弱事件模式。 此类方案之一是数据绑定。 在数据绑定中,源对象通常独立于作为绑定目标的侦听器对象。 WPF 数据绑定的许多方面已经在事件的实现方式上应用了弱事件模式。

4、如何实现弱事件模式

有四种方法可以实现弱事件模式,每种方法都使用不同的事件管理器。 选择最适合你的方案的事件管理器。

  • 现有弱事件管理器

    当要订阅的事件具有对应的 WeakEventManager,请使用现有的弱事件管理器。 有关 WPF 附带的弱事件管理器列表,请参阅 WeakEventManager 类中的继承层次结构。 由于包含的弱事件管理器有限,可能需要选择其他方法中的一个。


  • 通用弱事件管理器:

    如果现有的 WeakEventManager<TEventSource,TEventArgs> 事件不可用,并且你正在寻找实现弱事件的最简单方法,请使用泛型 WeakEventManager。 但是,泛型 WeakEventManager<TEventSource,TEventArgs> 比现有或自定义弱事件管理器更低效,因为它使用反射从其名称中发现事件。 此外,使用泛型 WeakEventManager<TEventSource,TEventArgs> 注册事件所需的代码比使用现有或自定义 WeakEventManager 注册事件所需的代码更详细。


  • 自定义弱事件管理器:

    在现有 WeakEventManager 不可用且效率至关重要时,创建自定义的 WeakEventManager。 尽管比泛型 WeakEventManager 更有效,但自定义 WeakEventManager 要求编写更多前期代码。

  • 第三方弱事件管理器:

  • 当需要其他方法未提供的功能时,请使用第三方弱事件管理器。 NuGet 具有一些较弱的事件管理器

以下部分介绍如何通过使用不同的事件管理器类型来实现弱事件模式。 对于泛型和自定义弱事件管理器示例,要订阅的事件具有以下特征。

  • 事件名称为 SomeEvent
  • 事件由 SomeEventSource 类引发。
  • 事件处理程序的类型为 EventHandler<SomeEventArgs>
  • 事件将 SomeEventArgs 类型的参数传递给事件处理程序。

4.1 使用现有弱事件管理器类

  1. 查找现有弱事件管理器。 有关 WPF 附带的弱事件管理器列表,请参阅 WeakEventManager 类的继承层次结构。

  2. 使用新的弱事件管理器,而不是普通事件挂钩。

    例如,如果代码使用以下模式订阅事件:

    source.LostFocus += new RoutedEventHandler(Source_LostFocus);
    

    将其更改为以下模式:

    LostFocusEventManager.AddHandler(source, Source_LostFocus);
    

    同样,如果代码使用以下模式取消订阅事件:

    source.LostFocus -= new RoutedEventHandler(Source_LostFocus);
    

    将其更改为以下模式:

    LostFocusEventManager.RemoveHandler(source, Source_LostFocus);
    

4.2 使用泛型弱事件管理器类

使用泛型 WeakEventManager<TEventSource,TEventArgs> 类,而不是普通事件挂钩。

使用 WeakEventManager<TEventSource,TEventArgs> 注册事件侦听器时,需要将事件源和 EventArgs 类型作为类型参数提供给类。 调用 AddHandler,如以下代码所示:

WeakEventManager<SomeEventSource, SomeEventArgs>.AddHandler(source, "SomeEvent", Source_SomeEvent);

4.3 创建自定义弱事件管理器类

  1. 将以下类模板复制到项目。 以下类继承自 WeakEventManager 类:

    class SomeEventWeakEventManager : WeakEventManager
    {private SomeEventWeakEventManager(){}/// <summary>/// Add a handler for the given source's event./// </summary>public static void AddHandler(SomeEventSource source,EventHandler<SomeEventArgs> handler){if (source == null)throw new ArgumentNullException(nameof(source));if (handler == null)throw new ArgumentNullException(nameof(handler));CurrentManager.ProtectedAddHandler(source, handler);}/// <summary>/// Remove a handler for the given source's event./// </summary>public static void RemoveHandler(SomeEventSource source,EventHandler<SomeEventArgs> handler){if (source == null)throw new ArgumentNullException(nameof(source));if (handler == null)throw new ArgumentNullException(nameof(handler));CurrentManager.ProtectedRemoveHandler(source, handler);}/// <summary>/// Get the event manager for the current thread./// </summary>private static SomeEventWeakEventManager CurrentManager{get{Type managerType = typeof(SomeEventWeakEventManager);SomeEventWeakEventManager manager =(SomeEventWeakEventManager)GetCurrentManager(managerType);// at first use, create and register a new managerif (manager == null){manager = new SomeEventWeakEventManager();SetCurrentManager(managerType, manager);}return manager;}}/// <summary>/// Return a new list to hold listeners to the event./// </summary>protected override ListenerList NewListenerList(){return new ListenerList<SomeEventArgs>();}/// <summary>/// Listen to the given source for the event./// </summary>protected override void StartListening(object source){SomeEventSource typedSource = (SomeEventSource)source;typedSource.SomeEvent += new EventHandler<SomeEventArgs>(OnSomeEvent);}/// <summary>/// Stop listening to the given source for the event./// </summary>protected override void StopListening(object source){SomeEventSource typedSource = (SomeEventSource)source;typedSource.SomeEvent -= new EventHandler<SomeEventArgs>(OnSomeEvent);}/// <summary>/// Event handler for the SomeEvent event./// </summary>void OnSomeEvent(object sender, SomeEventArgs e){DeliverEvent(sender, e);}
    }
    
  2. 重命名 SomeEventWeakEventManagerSomeEventSomeEventSource 和 SomeEventArgs 以匹配事件名称。

  3. 设置弱事件管理器类的
    访问修饰符,用于匹配其管理的事件的可访问性。

  4. 使用新的弱事件管理器,而不是普通事件挂钩。

    例如,如果代码使用以下模式订阅事件:

    source.SomeEvent += new EventHandler<SomeEventArgs>(Source_SomeEvent);
    

    将其更改为以下模式:

    SomeEventWeakEventManager.AddHandler(source, Source_SomeEvent);
    

    同样,如果代码使用以下模式取消订阅事件:

    source.SomeEvent -= new EventHandler<SomeEventArgs>(Source_SomeEvent);
    

    将其更改为以下模式:

    SomeEventWeakEventManager.RemoveHandler(source, Source_SomeEvent);
    

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

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

相关文章

DDoS 攻击并不是全部来自于PC组成的僵尸网络

DDoS&#xff0c;分布式拒绝服务攻击&#xff0c;是指处于不同位置的多个攻击者同时向一个或数个目标发动攻击&#xff0c;或者一个攻击者控制了位于不同位置的多台机器并利用这些机器对受害者同时实施攻击。很多人会以为DDoS 攻击&#xff0c;全都是攻击者控制PC肉鸡发起的攻击…

ELF文件信息一览

准备开个专栏&#xff0c;记录《从零开始实现链接器》的学习过程&#xff0c;先占个坑。 之前一直想把自己的学习过程记录在个人博客网站上&#xff0c;但这个要自己维护&#xff0c;上传图片什么的比较麻烦。关键是没有人互动&#xff0c;自己也没有怎么去看&#xff0c;慢慢的…

柯桥专业会计学校之相关财税知识,2023年新版增值税税率表

一、增值税税率 一般纳税人增值税税率&#xff1a;13%&#xff0c;9%&#xff0c;6%&#xff0c;0%&#xff0c;都适用于哪些项目&#xff1f;我们具体来看&#xff1a;&#xff08;目前小规模纳税人3%征收率减按1%执行&#xff09; 二、扣除率 扣除率是指增值税计征中法定扣除…

什么是DDOS 攻击?常见的DDOS攻击有哪些?

什么是DDoS攻击&#xff1f; DDoS攻击&#xff08;分布式拒绝服务攻击&#xff09;是一种旨在使计算机或网络资源不可用的恶意尝试。它通过使用多个受感染计算机&#xff08;称为僵尸网络&#xff09;同时向目标发送大量流量来实现这一目的&#xff0c;从而使目标不堪重负并崩溃…

【Bootstrap学习 day7】

Bootstrap按钮 按钮样式 使用.btn相关类实现 <button type"button" class"btn">基本按钮</button> <button type"button" class"btn btn-primary">主要按钮</button> <button type"button" cl…

【数据结构-单链表】(C语言版本)

今天分享的是数据结构有关单链表的操作和实践&#xff08;图解法&#xff0c;图变化更利于理解&#xff09; 记录宗旨&#x1f4dd;&#xff1a; 眼&#xff08;脑&#xff09;过千遍&#xff0c;不如手过一遍。 我们都知道单链表是一种常见的链表数据结构&#xff0c;由一系列…

【大数据】修复 Linux 错误 - 内存不足

修复 Linux 错误 - 内存不足 在使用 Linux 操作系统时,您可能会遇到内存不足的错误。这种错误通常会导致系统运行缓慢或崩溃。本文将介绍如何识别和修复 Linux 中的内存不足问题。 1. 检查内存使用情况 首先,您需要检查系统的内存使用情况。可以使用以下命令来查看当前内存…

【Java进阶篇】String中 intern 的原理是什么?

String中 intern 的原理 ✔️ 典型解析✔️小思考&#xff08;回顾&#xff09; ✔️字面量✔️intern✔️ intern原理✔️a和1有什么不同✔️答案 ✔️ 典型解析 字符串常量池中的常量有两种来源&#xff1a; 1、 字面量会在编译期先进入到Class常量池&#xff0c;然后再在运行…

配置ssh免密登录

1、cd ~ cd .ssh 输入ssh-keygen -t rsa 敲三次回车 [rootcdh-hadoop3 .ssh]# ssh-keygen -t rsa Generating public/private rsa key pair. Enter file in which to save the key (/root/.ssh/id_rsa): Enter passphrase (empty for no passphrase): Enter same passphrase…

milvus学习(一)cosin距离和欧式距离

参考&#xff1a;https://blog.csdn.net/qq_36560894/article/details/115408613 归一化以后的cosin距离和欧式距离可以相互转化&#xff0c;未归一化的不可以相互转化&#xff08;因为距离带单位&#xff09;。

C++多态性——(2)联编

归纳编程学习的感悟&#xff0c; 记录奋斗路上的点滴&#xff0c; 希望能帮到一样刻苦的你&#xff01; 如有不足欢迎指正&#xff01; 共同学习交流&#xff01; &#x1f30e;欢迎各位→点赞 &#x1f44d; 收藏⭐ 留言​&#x1f4dd; 成功的秘诀就在于多努力一次&#xff…

自动化测试中,如何增加失败重试机制!

01、前言 在执行自动化测试用例时&#xff0c;会发现有时候用例失败并非代码问题&#xff0c;而是由于服务正在发版&#xff0c;导致请求失败&#xff0c;从而降低了自动化用例的稳定性&#xff0c;最后还要花时间定位到底是自身case的原因还是业务逻辑问题&#xff0c;还是其…

电子招标采购系统源码之从供应商管理到采购招投标、采购合同、采购执行的全过程数字化管理

​随着市场竞争的加剧和企业规模的扩大&#xff0c;招采管理逐渐成为企业核心竞争力的重要组成部分。为了提高招采工作的效率和质量&#xff0c;我们提出了一种基于电子化平台的解决方案。该方案旨在通过电子化招投标&#xff0c;使得招标采购的质量更高、速度更快&#xff0c;…

宣传照(私密)勿转发

精美的海报通常都是由UI进行精心设计的&#xff0c;现在有100 件商品需要进行宣传推广&#xff0c;如果每个商品都出一张图显然是不合理的&#xff0c;且商品信息各异。因此需要通过代码的形式生成海报。对此&#xff0c;我也对我宣传一波&#xff0c;企图实现我一夜暴富的伟大…

贪心算法part04 860柠檬水找零 406根据身高重建队列

860 柠檬水找零 406 根据身高重建队列 452 用最少数量的箭引爆气球

使用java备份和恢复SQLServer表数据

需求 近来工作中遇到一个问题&#xff0c;内网办公系统中的数据需要导出到外网中进行查询&#xff0c;外网的数据库中还有一些表存储外网的数据&#xff0c;因此无法使用全库备份恢复功能来满足需求。即只从内网数据库中导出若干表的内容至外网数据库的对应表。 其他解决方案…

构建Python的Windows整合包教程

构建Python的Windows整合包教程 原文链接&#xff1a;https://blog.gcc.ac.cn/post/2023/buildpythonwindowsintegrationpackagetutorial/ 构建Python的Windows整合包教程 - 我的博客原文链接 前言 之前的开源项目本地素材搜索有很多人想要Windows整合包&#xff0c;因为Wi…

六、HTML 段落

HTML 可以将文档分割为若干段落。 一、HTML 段落 段落是通过 <p> 标签定义的。 <p>这是一个段落 </p> <p>这是另一个段落</p> 注意&#xff1a;浏览器会自动地在段落的前后添加空行。&#xff08;</p> 是块级元素&#xff09; 二、不…

[蓝桥杯知识学习] 树链

DFS序 什么是DFS序 怎么求DFS序 进入操作&#xff0c;将有计数 出&#xff1a;可以理解为&#xff0c;没有孩子可以去了&#xff08;不能&#xff0c;向下行动&#xff1a;对应于程序里的入栈&#xff09;&#xff0c;所以回到父结点&#xff08;向上行动&#xff0c;对应于程…

SCENIC+:增强子和基因调控网络的单细胞多组学推理

SCENIC&#xff1a;增强子和基因调控网络的单细胞多组学推理 摘要IntroductionSCENIC 使用超过 30,000 个 TF 基序来预测 eGRNSCENIC 在 PBMC 多组数据上的图示SCENIC prioritizes functional enhancers &#xff08;SCENIC 优先考虑功能增强剂&#xff09;SCENIC simulates ph…