WPF使用ItemsControl顯示Object的所有屬性值

對于上位機開發,我們有時候有這樣的需求:如何顯示所有的IO點位?比如有10個IO點位,那我們要寫10個TextBlock去綁定這10個點位的屬性(本文暫時不考慮顯示的樣式,當然也可以考慮),當點位變成了20個,我們要再加10TextBlock去顯示。
那么有沒有一種方法,直接顯示這個Object的所有屬性的值,當值發生變化,自動更新界面呢?這個需求不就類似于PropertyGrid嗎?但是我不想用PropertyGrid,我們使用ItemsControl去簡單的實現一下。

定義要顯示的IO點位

public class IOInfo : BindableBase{public IOInfo(){}private bool workLed1;public bool WorkLed1{get { return workLed1; }set { workLed1 = value; this.RaisePropertyChanged(nameof(WorkLed1)); }}private bool workLed2;public bool WorkLed2{get { return workLed2; }set { workLed2 = value; this.RaisePropertyChanged(nameof(WorkLed2)); }}private bool protectOn;public bool ProtectOn{get { return protectOn; }set { protectOn = value; this.RaisePropertyChanged(nameof(ProtectOn)); }}private bool pin1Status;public bool Pin1Status{get { return pin1Status; }set { pin1Status = value; this.RaisePropertyChanged(nameof(Pin1Status)); }}private bool pin2Status;public bool Pin2Status{get { return pin2Status; }set { pin2Status = value; this.RaisePropertyChanged(nameof(Pin2Status)); }}private bool cylinder1;public bool Cylinder1{get { return cylinder1; }set { cylinder1 = value; this.RaisePropertyChanged(nameof(Cylinder1)); }}private bool cylinder2;public bool Cylinder2{get { return cylinder2; }set { cylinder2 = value; this.RaisePropertyChanged(nameof(Cylinder2)); }}private bool bj;public bool BJ{get { return bj; }set { bj = value; this.RaisePropertyChanged(nameof(BJ)); }}private bool upSensor1;public bool UpSensor1{get { return upSensor1; }set { upSensor1 = value; this.RaisePropertyChanged(nameof(UpSensor1)); }}private bool upSensor2;public bool UpSensor2{get { return upSensor2; }set { upSensor2 = value; this.RaisePropertyChanged(nameof(UpSensor2)); }}private bool airPressure;public bool AirPressure{get { return airPressure; }set { airPressure = value; this.RaisePropertyChanged(nameof(AirPressure)); }}private bool doorStatus;public bool DoorStatus{get { return doorStatus; }set { doorStatus = value; this.RaisePropertyChanged(nameof(DoorStatus)); }}private bool smokeStatus;public bool SmokeStatus{get { return smokeStatus; }set { smokeStatus = value; this.RaisePropertyChanged(nameof(SmokeStatus)); }}private bool tempStatus;public bool TempStatus{get { return tempStatus; }set { tempStatus = value; this.RaisePropertyChanged(nameof(TempStatus)); }}private bool remoteStatus;public bool RemoteStatus{get { return remoteStatus; }set { remoteStatus = value; this.RaisePropertyChanged(nameof(RemoteStatus)); }}private bool trayStatus;public bool TrayStatus{get { return trayStatus; }set { trayStatus = value; this.RaisePropertyChanged(nameof(TrayStatus)); }}private bool startStatus;public bool StartStatus{get { return startStatus; }set { startStatus = value; this.RaisePropertyChanged(nameof(StartStatus)); }}private bool powerStatus;public bool PowerStatus{get { return powerStatus; }set { powerStatus = value; this.RaisePropertyChanged(nameof(PowerStatus)); }}private bool emergencyStatus;public bool EmergencyStatus{get { return emergencyStatus; }set { emergencyStatus = value; this.RaisePropertyChanged(nameof(EmergencyStatus)); }}private bool errTrace;public bool ErrorTrace{get { return errTrace; }set { errTrace = value; this.RaisePropertyChanged(nameof(ErrorTrace)); }}}

上述的BindableBase是引用了Prism框架

定義轉換器

無論是ItemsControl還是PropertyGrid最終顯示到界面的時候,都是一個集合。我們需要把object使用轉換器轉換為集合,轉換為集合之前,首先定義ItemsControl要顯示的Model:

public class PropertyAndValue : BindableBase{private string propertyName;/// <summary>/// 屬性名稱/// </summary>public string PropertyName{get { return propertyName; }set { propertyName = value; this.RaisePropertyChanged(nameof(PropertyName)); }}private string propertyNameAlias;/// <summary>/// 顯示的別名,如果沒有定義,則和屬性名稱一致/// </summary>public string PropertyNameAlias{get { return propertyNameAlias; }set { propertyNameAlias = value; this.RaisePropertyChanged(nameof(PropertyNameAlias)); }}private object propertyValue;/// <summary>/// 屬性的值/// </summary>public object PropertyValue{get { return propertyValue; }set { propertyValue = value; this.RaisePropertyChanged(nameof(PropertyValue)); }}}

將轉換器轉換為Model的集合,這里重點要思考的是,IOInfo的屬性變化,如何去更新界面,我采用簡單粗暴的方式是手動訂閱PropertyChanged事件:

public class IOStatusConverter : IValueConverter{private List<PropertyAndValue> values = new List<PropertyAndValue>();private IOInfo ioInfo = null;public object Convert(object value, Type targetType, object parameter, CultureInfo culture){if (value == null || !(value is IOInfo ioInfo)) return value;ioInfo.PropertyChanged += IoInfo_PropertyChanged;foreach (var property in typeof(IOInfo).GetProperties()){values.Add(new PropertyAndValue() { PropertyName = property.Name, PropertyNameAlias = property.Name, PropertyValue = property.GetValue(ioInfo) }); }return values;}private void IoInfo_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e){var v = values.FirstOrDefault(x => x.PropertyName == e.PropertyName);if (v == null) return;var property = typeof(IOInfo).GetProperty(e.PropertyName);if (property == null) return;v.PropertyValue = property.GetValue(sender);}public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture){return Binding.DoNothing;}}

前臺界面綁定

xaml的代碼如下:

<ItemsControl Grid.Row="1" ItemsSource="{Binding IO,Converter={StaticResource IOStatusConverter}}"><ItemsControl.ItemTemplate><DataTemplate><StackPanel Orientation="Horizontal"><TextBlock Text="{Binding PropertyName}" /><TextBlock Text=":" /><TextBlock Text="{Binding PropertyValue}" /></StackPanel></DataTemplate></ItemsControl.ItemTemplate>
</ItemsControl>

最終實現的效果

在這里插入圖片描述
點擊上方的修改按鈕,它能更新界面的屬性值。

改進

屬性名稱顯示別名

要顯示別名,我們要經過3個步驟。

  • 獲取要顯示的別名
  • 將別名賦值到PropertyNameAlias屬性
  • PropertyNameAlias綁定到界面

我們使用DescriptionAttribute標簽來實現別名,更改后的IOInfo類如下:

public class IOInfo : BindableBase{public IOInfo(){}private bool workLed1;[Description("燈1")]public bool WorkLed1{get { return workLed1; }set { workLed1 = value; this.RaisePropertyChanged(nameof(WorkLed1)); }}private bool workLed2;[Description("燈2")]public bool WorkLed2{get { return workLed2; }set { workLed2 = value; this.RaisePropertyChanged(nameof(WorkLed2)); }}private bool protectOn;public bool ProtectOn{get { return protectOn; }set { protectOn = value; this.RaisePropertyChanged(nameof(ProtectOn)); }}private bool pin1Status;public bool Pin1Status{get { return pin1Status; }set { pin1Status = value; this.RaisePropertyChanged(nameof(Pin1Status)); }}private bool pin2Status;public bool Pin2Status{get { return pin2Status; }set { pin2Status = value; this.RaisePropertyChanged(nameof(Pin2Status)); }}private bool cylinder1;public bool Cylinder1{get { return cylinder1; }set { cylinder1 = value; this.RaisePropertyChanged(nameof(Cylinder1)); }}private bool cylinder2;public bool Cylinder2{get { return cylinder2; }set { cylinder2 = value; this.RaisePropertyChanged(nameof(Cylinder2)); }}private bool bj;public bool BJ{get { return bj; }set { bj = value; this.RaisePropertyChanged(nameof(BJ)); }}private bool upSensor1;public bool UpSensor1{get { return upSensor1; }set { upSensor1 = value; this.RaisePropertyChanged(nameof(UpSensor1)); }}private bool upSensor2;public bool UpSensor2{get { return upSensor2; }set { upSensor2 = value; this.RaisePropertyChanged(nameof(UpSensor2)); }}private bool airPressure;public bool AirPressure{get { return airPressure; }set { airPressure = value; this.RaisePropertyChanged(nameof(AirPressure)); }}private bool doorStatus;public bool DoorStatus{get { return doorStatus; }set { doorStatus = value; this.RaisePropertyChanged(nameof(DoorStatus)); }}private bool smokeStatus;public bool SmokeStatus{get { return smokeStatus; }set { smokeStatus = value; this.RaisePropertyChanged(nameof(SmokeStatus)); }}private bool tempStatus;public bool TempStatus{get { return tempStatus; }set { tempStatus = value; this.RaisePropertyChanged(nameof(TempStatus)); }}private bool remoteStatus;public bool RemoteStatus{get { return remoteStatus; }set { remoteStatus = value; this.RaisePropertyChanged(nameof(RemoteStatus)); }}private bool trayStatus;public bool TrayStatus{get { return trayStatus; }set { trayStatus = value; this.RaisePropertyChanged(nameof(TrayStatus)); }}private bool startStatus;public bool StartStatus{get { return startStatus; }set { startStatus = value; this.RaisePropertyChanged(nameof(StartStatus)); }}private bool powerStatus;public bool PowerStatus{get { return powerStatus; }set { powerStatus = value; this.RaisePropertyChanged(nameof(PowerStatus)); }}private bool emergencyStatus;public bool EmergencyStatus{get { return emergencyStatus; }set { emergencyStatus = value; this.RaisePropertyChanged(nameof(EmergencyStatus)); }}private bool errTrace;public bool ErrorTrace{get { return errTrace; }set { errTrace = value; this.RaisePropertyChanged(nameof(ErrorTrace)); }}}

我們在WorkLed1WorkLed2這兩個屬性上打了兩個標簽,界面顯示的時候,我們希望顯示我們打上的標簽的值。
現在我們把轉換器修改下:

public class IOStatusConverter : IValueConverter{private List<PropertyAndValue> values = new List<PropertyAndValue>();private IOInfo ioInfo = null;public object Convert(object value, Type targetType, object parameter, CultureInfo culture){if (value == null || !(value is IOInfo ioInfo)) return value;ioInfo.PropertyChanged += IoInfo_PropertyChanged;foreach (var property in typeof(IOInfo).GetProperties()){var propertyName=property.Name;var propertyNameAlias = property.GetCustomAttribute<DescriptionAttribute>()?.Description ?? propertyName;values.Add(new PropertyAndValue() { PropertyName = propertyName, PropertyNameAlias = propertyNameAlias, PropertyValue = property.GetValue(ioInfo) }); }return values;}private void IoInfo_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e){var v = values.FirstOrDefault(x => x.PropertyName == e.PropertyName);if (v == null) return;var property = typeof(IOInfo).GetProperty(e.PropertyName);if (property == null) return;v.PropertyValue = property.GetValue(sender);}public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture){return Binding.DoNothing;}}

界面顯示綁定修改綁定到PropertyNameAlias屬性:

<ItemsControl Grid.Row="1" ItemsSource="{Binding IO, Converter={StaticResource IOStatusConverter}}"><ItemsControl.ItemTemplate><DataTemplate><StackPanel Orientation="Horizontal"><TextBlock Text="{Binding PropertyNameAlias}" /><TextBlock Text=":" /><TextBlock Text="{Binding PropertyValue}" /></StackPanel></DataTemplate></ItemsControl.ItemTemplate>
</ItemsControl>

最后的顯示效果:
在這里插入圖片描述

轉換器的改進

通用轉換器:

public class ObjectToListBaseConverter<T> : IValueConverter where T:INotifyPropertyChanged{private List<PropertyAndValue> values = new List<PropertyAndValue>();public object Convert(object value, Type targetType, object parameter, CultureInfo culture){if (value == null || !(value is T obj)) return value;//如果不是T的類型,則返回obj.PropertyChanged += Obj_PropertyChanged;foreach (var property in typeof(IOInfo).GetProperties()){var propertyName = property.Name;var propertyNameAlias = property.GetCustomAttribute<DescriptionAttribute>()?.Description ?? propertyName;values.Add(new PropertyAndValue() { PropertyName = propertyName, PropertyNameAlias = propertyNameAlias, PropertyValue = property.GetValue(obj) });}return values;}private void Obj_PropertyChanged(object sender, PropertyChangedEventArgs e){var v = values.FirstOrDefault(x => x.PropertyName == e.PropertyName);if (v == null) return;var property = typeof(T).GetProperty(e.PropertyName);if (property == null) return;v.PropertyValue = property.GetValue(sender);}public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture){return Binding.DoNothing;}}

IOStatusConverter修改如下,做到了代碼的通用:

public class IOStatusConverter : ObjectToListBaseConverter<IOInfo>
{}

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/13303.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/13303.shtml
英文地址,請注明出處:http://en.pswp.cn/web/13303.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

springboot整合swagger,jpa遇到的問題

1.整合jpa&#xff0c;版本問題導致Archive for required library: ‘C:/Users/Administrator/.m2/repository/org/aspectj/aspectjweaver/1.8.13/aspectjweaver-1.8.13.jar’ in project ‘money-server’ cannot be read or is not a valid ZIP file money-server Build path…

Leetcode 257:二叉樹的所有路徑

給你一個二叉樹的根節點 root &#xff0c;按 任意順序 &#xff0c;返回所有從根節點到葉子節點的路徑。 葉子節點 是指沒有子節點的節點。 思路&#xff1a; 先編輯所有節點&#xff0c;記錄每一個節點的路徑&#xff1b; 判斷當前節點是否為葉子節點&#xff0c;如果是&…

霍庭格TruPlasma MF 7100 7050電源現貨50KW

霍庭格TruPlasma MF 7100 7050電源現貨50KW

mysql json 數組怎么搜索

在MySQL中&#xff0c;可以使用JSON_CONTAINS函數來搜索JSON數組中的元素。這里有一個簡單的例子&#xff1a; 假設有一個名為items的表&#xff0c;其中有一個名為attributes的列&#xff0c;包含JSON數組。 CREATE TABLE items (id INT AUTO_INCREMENT PRIMARY KEY,attribu…

SQLSERVER 怎樣使查詢不占鎖

對一些相對不怎么敏感的數據&#xff0c;不需要太及時性的數據&#xff0c;不需要占鎖。 要在SQL Server中執行查詢而不占用鎖&#xff0c;可以采取以下幾個策略&#xff1a; 1、使用NOLOCK提示&#xff1a; 最直接但風險較高的方法是在查詢中使用WITH (NOLOCK)提示。這樣&am…

練習題(2024/5/16)

1輪轉數組 給定一個整數數組 nums&#xff0c;將數組中的元素向右輪轉 k 個位置&#xff0c;其中 k 是非負數。 示例 1: 輸入: nums [1,2,3,4,5,6,7], k 3 輸出: [5,6,7,1,2,3,4] 解釋: 向右輪轉 1 步: [7,1,2,3,4,5,6] 向右輪轉 2 步: [6,7,1,2,3,4,5] 向右輪轉 3 步: [5,…

【C語言深度解剖】:(11)函數指針、函數指針數組、指向函數指針數組的指針、回調函數

&#x1f921;博客主頁&#xff1a;醉竺 &#x1f970;本文專欄&#xff1a;《C語言深度解剖》《精通C指針》 &#x1f63b;歡迎關注&#xff1a;感謝大家的點贊評論關注&#xff0c;祝您學有所成&#xff01; ??&#x1f49c;&#x1f49b;想要學習更多C語言深度解剖點擊專欄…

AVDemo漏洞平臺黑盒測試

信息收集 說明一下&#xff1a; 因為是本地的環境&#xff0c;端口這些就不掃描了&#xff0c; 還有這個是某個dalao寫的平臺&#xff0c;也就檢測不到什么cms了&#xff0c; 信息收集&#xff0c;端口&#xff0c;cms這些是必做的&#xff0c; 首先&#xff0c;這里先簡單的…

web3 ETF軟件開發難點

開發一個涉及到 Web3 ETF&#xff08;Exchange-Traded Fund&#xff0c;交易所交易基金&#xff09;的軟件可能會面臨一些挑戰和難點&#xff0c;特別是在整合 Web3 技術和金融服務方面。以下是一些可能的難點。北京木奇移動技術有限公司&#xff0c;專業的軟件外包開發公司&am…

記一次:mysql統計的CAST函數與json字段中的某個字段

前言&#xff1a;因為需求的問題&#xff0c;會遇到將某個json存入到一個字段中&#xff0c;但在統計的時候&#xff0c;又需要將這個json中的某個字段作為條件來統計&#xff0c;所以整理了一下cast函數和json中某個字段的條件判斷 一、淺談mysql的json 1.1 上例子 SELECTli…

植物大戰僵尸雜交版(含下載方式)

最近時間&#xff0c;一款很火的植物大戰僵尸雜交版火爆出圈&#xff0c;在玩家之間瘋狂擴散。各種奇特的雜交組合讓游戲變得更加有趣。 游戲介紹 植物大戰僵尸雜交版是一款將《植物大戰僵尸》和植物雜交概念結合在一起的獨特塔防策略游戲。它將《植物大戰僵尸》中的植物與進行…

什么是析構函數?

在編程語言C中&#xff0c;析構函數是一個特別重要的組件&#xff0c;它主要負責在對象生命周期結束時釋放資源和執行清理任務。析構函數的正確實現對于資源管理尤為關鍵&#xff0c;尤其是在處理動態分配內存、文件句柄、網絡連接或其他系統資源時。本文將詳細介紹析構函數的基…

Minio 對象存儲 OSS概述

系列文章目錄 第五章 Minio 對象存儲 OSS概述 Minio 對象存儲 OSS概述 系列文章目錄對象存儲 OSS基本概念存儲空間&#xff08;Bucket&#xff09;對象&#xff08;Object&#xff09;ObjectKeyRegion&#xff08;地域&#xff09;Endpoint&#xff08;訪問域名&#xff09;Ac…

C#知識|上位機子窗體嵌入主窗體方法(實例)

哈嘍,你好啊,我是雷工! 上位機開發中,經常會需要將子窗體嵌入到主窗體, 本節練習C#中在主窗體的某個容器中打開子窗體的方法。 01 需求說明 本節練習將【賬號管理】子窗體在主窗體的panelMain容器中打開。 賬號管理子窗體如下: 主窗體的panelMain容器位置如圖: 02 實現…

一次JAVA接口優化記錄

目錄 一次接口優化記錄首先考慮&#xff0c;添加緩存緩存策略方案一&#xff1a;本地緩存方案二&#xff1a;Redis緩存 優化結果原因分析&#xff1a;原因驗證 接口數據分析將響應數據返回大小減少compression壓縮配置完美&#xff08;代指這里的小系統&#xff09; 一次接口優…

CentOS 的常見命令

CentOS 是一種廣泛使用的 Linux 發行版&#xff0c;特別在服務器環境中。本文將詳細介紹 CentOS 中常見的命令&#xff0c;以便幫助用戶在操作系統中有效地進行各種操作。下面介紹一下文件和目錄操作、用戶和權限管理、系統信息查看、軟件包管理以及網絡配置等方面的命令。 一…

應用層協議【HTTP和HTTPS】

1.概念 1.1 協議 協議是指在計算機通信和網絡通信中&#xff0c;為了實現數據交換而建立的一套規則、約定或者標準。它定義了通信雙方之間的通信格式、傳輸方式、數據的含義、錯誤處理等細節&#xff0c;從而確保通信的可靠性、有效性和安全性。 >1在計算機網絡中&#x…

Python簡易圖書管理系統重構

在本篇課文中&#xff0c;我們將使用Python語言結合MySQL數據庫&#xff0c;從零開始構建一個簡單的圖書管理系統。該系統旨在幫助圖書館管理員輕松管理圖書的借閱、歸還以及查詢圖書信息等日常操作。我們將分步介紹需求分析、數據庫設計、環境搭建、功能實現等關鍵環節&#x…

注冊講堂 | 體外診斷試劑分類目錄的變化

5月11日&#xff0c;千呼萬喚的《體外診斷試劑分類目錄》&#xff08;2024年第58號&#xff09;終于發布&#xff01; 前世今生 2013年&#xff1a;《6840 體外診斷試劑分類子目錄&#xff08;2013版&#xff09;》&#xff08;以下簡稱2013版目錄&#xff09; 2017年&#xff…