1.AI帮忙定义新用户控件

2.在属性上添加TelerikEditorAttribute特性

 private ObservableCollection<string> _axisOrder;[Display(Description = "点位", GroupName = "通用", Name = "轴&顺序", Order = 1)][DataMember][TelerikEditorAttribute(typeof(DoubleListBoxEditor), "SelectedItems")]public ObservableCollection<string> AxisOrder{get => _axisOrder;set => this.RaiseAndSetIfChanged(ref _axisOrder, value);}
[TelerikEditorAttribute(typeof(DoubleListBoxEditor), "SelectedItems")]

SelectedItems属性可以根据实体情况进行更换;

3.效果

4.扩展

这个编辑控件包含了两个ListBox,我想根据实体的其他属性变更然后变更其中一个ListBox的数据源:

思路就是在DoubleListBoxEditor类里面监听这个属性变化,要挂载事件;

要想找到这个属性的事件就得找到对应的实体;

(要有控件的Parent属性, 视觉树这些概念)

使用自定义Editor控件的Parent属性,可以得到对应的在PropertyGrid中对应的条目包装:

在这个包装中找到DataContext属性得到对应的实体属性包装;

然后再找到Instance属性得到对应实体,再得到对应想拿到的属性;

挂载事件的时机要把控好,不能写在构造函数里,此时界面对象还未赋值;

代码:

  public override void OnApplyTemplate(){base.OnApplyTemplate();if (!(Parent is PropertyGridField field)){return;}var def = (PropertyDefinition)field.DataContext;CustomPropertyDescriptor pd = null;if (def.Instance is MovePositionActionNode node){node.PropertyChanged -= PositionPropertyChanged;node.PropertyChanged += PositionPropertyChanged;}}

更新:

测试中发现会多次调用PositionPropertyChanged方法,和我预想的结果不同,因为我的写法是:

node.PropertyChanged -= PositionPropertyChanged;
 node.PropertyChanged += PositionPropertyChanged;

本来想的是始终只会挂载一个方法上去,但是测试的时候发现每调用一次OnApplyTemplate(),就会多挂载一个方法上去。

原因:

在 C# 中,委托实际上是对象(继承自 System.MulticastDelegate)。每次使用方法名创建委托时,都会在堆上创建一个新的委托对象实例。

写一段代码模拟上面出现的bug:

 public class EventSource{public event EventHandler Event;public void RaiseEvent(){Event.Invoke(null,null);}}public class Example{public void MyMethod(object sender, EventArgs e) { Console.WriteLine("Hello, World!"); }}

然后这样调用:

 EventSource obj = new EventSource();for (int i = 0; i < 3; i++){Example ex = new Example();obj.Event -= ex.MyMethod;obj.Event += ex.MyMethod;}obj.RaiseEvent();

结果会调用三次MyMethod,因为我的代码中,执行OnApplyTemplate时都是新创建对象的时候,所以效果类似这段测试代码;

查看IL:

node.PropertyChanged -= PositionPropertyChanged;
 node.PropertyChanged += PositionPropertyChanged;

  IL_0045: ldloc.2      // nodeIL_0046: ldarg.0      // thisIL_0047: ldftn        instance void Lithography.Model.ActionAbout.UI.DoubleListBoxEditor::PositionPropertyChanged(object, class [System]System.ComponentModel.PropertyChangedEventArgs)IL_004d: newobj       instance void [System]System.ComponentModel.PropertyChangedEventHandler::.ctor(object, native int)IL_0052: callvirt     instance void [ReactiveUI]ReactiveUI.ReactiveObject::remove_PropertyChanged(class [System]System.ComponentModel.PropertyChangedEventHandler)IL_0057: nop// [82 17 - 82 65]IL_0058: ldloc.2      // nodeIL_0059: ldarg.0      // thisIL_005a: ldftn        instance void Lithography.Model.ActionAbout.UI.DoubleListBoxEditor::PositionPropertyChanged(object, class [System]System.ComponentModel.PropertyChangedEventArgs)IL_0060: newobj       instance void [System]System.ComponentModel.PropertyChangedEventHandler::.ctor(object, native int)IL_0065: callvirt     instance void [ReactiveUI]ReactiveUI.ReactiveObject::add_PropertyChanged(class [System]System.ComponentModel.PropertyChangedEventHandler)IL_006a: nop

挂载对象前创建了一个PropertyChangedEventHandler对象,对应着上方:委托实际上是对象(继承自 System.MulticastDelegate)。每次使用方法名创建委托时,都会在堆上创建一个新的委托对象实例。

也就是说+=操作符相当于执行了Add_TestEvent(new Action(memory.Run)),就是这个new Action包含了对memory指向的内存的引用。而这个引用在CLR看来是可达的,可以通过引发事件来调用该内存,所以这种情况会有内存泄漏的风险。

引用:https://blog.csdn.net/nodeathphoenix/article/details/84549399?fromshare=blogdetail&sharetype=blogdetail&sharerId=84549399&sharerefer=PC&sharesource=qq_59062726&sharefrom=from_link

防止内存泄漏解决办法:

1.在界面对象销毁前,主动取消订阅

新添加一个字段保存事件发布者的对象:

private MovePositionActionNode _currentNode;

然后在界面Loaded事件里订阅事件,Unloaded事件里取消订阅:

 private void OnLoaded(object sender, RoutedEventArgs e){// 通过视觉树找到PropertyGridItemvar propertyGridItem = VisualTreeExtensions.FindParent<PropertyGridField>(this);var def = (PropertyDefinition)propertyGridItem.DataContext;if (def.Instance is MovePositionActionNode node){_currentNode = node;_currentNode.PropertyChanged += OnNodePropertyChanged;UpdateAvailableItemsBasedOnPositionType(node.EquipmentPositionType);}}private void OnUnloaded(object sender, RoutedEventArgs e){if (_currentNode != null){_currentNode.PropertyChanged -= OnNodePropertyChanged;_currentNode = null;}}

辅助方法:

// 辅助方法:在视觉树中查找父元素
public static T FindParent<T>(DependencyObject child) where T : DependencyObject
{var parent = VisualTreeHelper.GetParent(child);while (parent != null && !(parent is T)){parent = VisualTreeHelper.GetParent(parent);}return parent as T;
}

2.使用弱引用事件:WeakEventManager
 // 保存委托引用private PropertyChangedEventHandler _positionPropertyChangedHandler;//发布者对象引用private MovePositionActionNode _currentNode;
 public override void OnApplyTemplate(){base.OnApplyTemplate();if (!(Parent is PropertyGridField field)){return;}var def = (PropertyDefinition)field.DataContext;if (def.Instance is MovePositionActionNode node){// 移除旧节点的订阅if (_currentNode != null){WeakEventManager<MovePositionActionNode, PropertyChangedEventArgs>.RemoveHandler(_currentNode,nameof(INotifyPropertyChanged.PropertyChanged),OnNodePropertyChanged);}// 订阅新节点_currentNode = node;WeakEventManager<MovePositionActionNode, PropertyChangedEventArgs>.AddHandler(node,nameof(INotifyPropertyChanged.PropertyChanged),OnNodePropertyChanged);UpdateAvailableItemsBasedOnPositionType(node.EquipmentPositionType);}}

引用1:https://www.cnblogs.com/monkeyZhong/p/4596914.html

引用2:https://blog.csdn.net/weixin_30621959/article/details/97911511?fromshare=blogdetail&sharetype=blogdetail&sharerId=97911511&sharerefer=PC&sharesource=qq_59062726&sharefrom=from_link

.Net中的事件有时会引起内存泄露问题。例如,A注册了B的某个事件,此时B就会暗中保留A的一个强引用,导致A无法被内存回收,直到B被回收或A反注册了B的事件。例如,我有一个对象注册了主窗口的Loaded事件,只要我不反注册该事件,那么主窗口会一直引用该对象,直到主窗口被关闭,该对象才会被回收。所以,每当我们注册某个对象的事件时,都有可能在不经意间埋下内存泄露的隐患。

解决这个问题的根本方法是,在必要的时候进行事件的反注册。但是,在某些情况下,我们可能很难判定这个“必要的时候”。另外,当我们作为类库的提供者时,我们也很难保证类库的使用者都记得要反注册事件。因此,另一个解决方案就是使用弱事件。

弱事件的实现原理很简单,就是对事件进行一层封装。不让事件发布者直接引用监听者,而是让他们保留一个监听者的弱引用。当事件触发时,发布者会先检查监听者是否还存在于内存中,如果存在才通知它。如此一来,监听者的生命周期就不会依赖于发布者了。

-------------------------------------------------------------------------------------------------

此番论述,未尽其详。乞盼来日,续有心得,再行补益。

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

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

相关文章

【超详细】别再看零散的教程了!一篇搞定Gitee从注册、配置到代码上传与管理(内含避坑指南最佳实践)

&#x1f525;个人主页&#xff1a;艾莉丝努力练剑 ❄专栏传送门&#xff1a;《C语言》、《数据结构与算法》、C语言刷题12天IO强训、LeetCode代码强化刷题、洛谷刷题、C/C基础知识知识强化补充、C/C干货分享&学习过程记录 &#x1f349;学习方向&#xff1a;C/C方向学习者…

43.shell脚本循环与函数

shell脚本循环与函数 for 循环 for 循环用于一次性读取多个信息&#xff0c;逐一对信息进行操作处理&#xff0c;特别适合处理有范围的数据 语法 for 变量名 in 取值列表 do命令序列 done批量创建用户 #!/bin/bashtouch /root/users.txt echo aka blues cloe dio foks > /ro…

模型部署:(四)安卓端部署Yolov8-v8.2.99实例分割项目全流程记录

模型部署&#xff1a;&#xff08;四&#xff09;安卓端部署Yolov8-v8.2.99实例分割项目全流程记录1、下载ncnn2、下载opencv-mobile3、文件拷贝4、andorid_studio相关配置5、文件内参数设置5、重构项目&#xff1a;6、打包apk7、部署自己训练的实例分割模型1、下载ncnn 地址&…

高并发、低延迟全球直播系统架构

一、 核心架构图 整个系统的数据流和工作流程如下图所示&#xff0c;它清晰地展示了从主播推流到观众观看的完整过程&#xff1a; #mermaid-svg-QzNpj0DWxd5FERPC {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-QzN…

AWS strands agents 当智能体作为独立服务/容器部署时,它们无法共享进程内状态

当智能体作为独立服务/容器部署时&#xff0c;它们无法共享进程内状态。 以下是针对分布式部署中动态内存库的生产就绪解决方案&#xff1a;1. 基于外部存储的内存库基于 DynamoDB 的共享内存import boto3 from strands import Agent, tool from typing import Dict, Any impor…

第五节 JavaScript——引用类型、DOM/BOM 与异步编程

JavaScript 的第五节课通常会深入探讨 ​​引用类型、DOM 操作、BOM 操作、事件处理以及异步编程​​ 等核心概念。这些知识能让你创建动态交互丰富的网页。下面我将详细讲解这些内容并提供示例。 🚀 JavaScript 第五节:引用类型、DOM/BOM 与异步编程 ⚡ 一、引用类型 引…

使用Pycharm进行远程ssh(以Featurize为例)

使用Pycharm进行远程ssh&#xff08;以Featurize为例&#xff09;文章目录介绍应用背景远程连接Python连接Jupyter介绍应用背景 在使用Pycharm 专业版的时候进行远程ssh连接服务器&#xff08;Featurize&#xff09;的Python解释器和Jupyter 远程连接Python 打开Pycharm点击…

深入研究:ClickHouse中arrayExists与hasAny在ORDER BY场景下的性能差异

最近公司大数据情况下ClickHouse查询性能极差&#xff0c;后来发现在大数据量ORDER BY场景下&#xff0c;arrayExists(x -> x in ...)比hasAny性能快10倍&#xff01;&#xff01;&#xff01;&#xff01; 一、问题重述与研究背景 在大数据量 ORDER BY场景下&#xff0c;…

Spring AI (二)结合Mysql做聊天信息存储

上文讲了&#xff0c;用Spring ai做简单的聊天功能&#xff0c;没看过的可以查看下 Spring AI结合豆包模型 这里简单结合下Jdbc做下聊天记录的存储和查询&#xff0c;让对话变的更智能。 首先是Pom的支持 <dependency><groupId>org.springframework.ai</grou…

【docker】data-root 数据迁移(防止无法加载镜像和容器问题)

操作系统&#xff1a;ubuntu 24.04 docker版本&#xff1a;docker-ce 28.1.1 目标&#xff1a;将/var/lib/docker 的数据迁移到/data/docker停止docker sudo systemctl stop docker.socket sudo systemctl stop docker这个步骤一定要做&#xff0c;否则容易导致数据不一致。 rs…

二、网页的“化妆师”:从零学习 CSS

一、CSS 是什么 1.1 CSS 的定义 CSS&#xff08;Cascading Style Sheets&#xff0c;层叠样式表&#xff09; 是一种用来给 HTML 页面 添加样式的语言。 简单来说&#xff1a; HTML 负责结构 —— 决定网页上有什么内容。 CSS 负责样式 —— 决定这些内容“长什么样”。 如果…

传统项目管理与敏捷的核心差异

在项目管理领域&#xff0c;传统方法与敏捷方法代表了两种不同的管理思维与实践路径。传统项目管理强调计划性、规范性和阶段性推进&#xff0c;而敏捷则注重灵活性、快速迭代和价值交付。 正如彼得德鲁克所说&#xff1a;“没有完美的计划&#xff0c;只有不断调整的行动。”理…

axios+ts封装

http.ts import axios from axios import type { AxiosInstance, AxiosRequestConfig, AxiosResponse } from axios import qs from qs/*** 扩展AxiosRequestConfig&#xff0c;增加一些自定义的属性* isAuth: 自定义的参数中&#xff0c;用来判断是否携带token 因为AxiosReq…

2026新选题:基于K-Means实现学生求职意向聚类推荐职位

作者简介&#xff1a;Java领域优质创作者、CSDN博客专家 、CSDN内容合伙人、掘金特邀作者、阿里云博客专家、51CTO特邀作者、多年架构师设计经验、多年校企合作经验&#xff0c;被多个学校常年聘为校外企业导师&#xff0c;指导学生毕业设计并参与学生毕业答辩指导&#xff0c;…

SpringCloud gateway配置predicates的匹配规则

需求 通过gateway的route规则&#xff0c;实现分组流量配置 资源 一个nacos&#xff0c;一个gateway &#xff0c;一个服务app&#xff08;部署双实例group-1&#xff0c;group-2&#xff09;&#xff0c;实现特定条件下往分组一和分组二流量切换。 方案 1 配置文件 nacos…

android14 硬键盘ESC改BACK按键返回无效问题

在之前的android版本中修改外接键盘ESC为BACK按键做返回键使用&#xff0c;直接修改如下代码即可&#xff1a;--- a/frameworks/base/data/keyboards/Generic.kcmb/frameworks/base/data/keyboards/Generic.kcm-499,7 499,7 key PLUS {### Non-printing keys ###key ESCAPE { …

【开题答辩全过程】以 asp高校外卖订单系统的设计与实现为例,包含答辩的问题和答案

个人简介一名14年经验的资深毕设内行人&#xff0c;语言擅长Java、php、微信小程序、Python、Golang、安卓Android等开发项目包括大数据、深度学习、网站、小程序、安卓、算法。平常会做一些项目定制化开发、代码讲解、答辩教学、文档编写、也懂一些降重方面的技巧。感谢大家的…

UVa1063/LA3807 The Rotation Game

UVa1063/LA3807 The Rotation Game题目链接题意输入格式输出格式分析AC 代码IDA*分3次BFS题目链接 本题是2004年icpc亚洲区域赛上海赛区的H题 题意 如下图所示形状的棋盘上分别有8个1、2、3&#xff0c;要往A&#xff5e;H方向旋转棋盘&#xff0c;使中间8个方格数字相同。图&…

用pywin32连接autocad 写一个利用遗传算法从选择的闭合图形内进行最优利用率的排版 ai草稿

好的&#xff0c;我们来深入细说遗传算法&#xff08;Genetic Algorithm, GA&#xff09;在钣金自动排版中的应用。遗传算法 (GA) 在钣金排版中的详细解析遗传算法是一种受达尔文生物进化论启发的元启发式优化算法。它不追求一次性找到数学上的绝对最优解&#xff0c;而是通过模…

Go语言io.Copy深度解析:高效数据复制的终极指南

在日常开发中&#xff0c;我们经常需要在不同的数据源之间复制数据。无论是文件操作、网络传输还是进程通信&#xff0c;数据复制都是不可或缺的基础操作。Go语言的标准库提供了一个强大而高效的工具来简化这一过程&#xff1a;io.Copy。 什么是io.Copy&#xff1f; io.Copy是G…