WPF Telerik.Windows.Controls.Data.PropertyGrid 自定義屬性編輯器

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…