學WinForm也就半年,然後轉到WPF,還在熟悉中。最近拿到一個任務:從PropertyGrid控制項,輸出內容到Word。難點有: 一.PropertyGrid控制項是WinForm控制項,在WPF中並不能直接從工具箱獲得,或者直接在XMAL中聲明使用。 如要使用,需要使用WindowFormHost ...
學WinForm也就半年,然後轉到WPF,還在熟悉中。最近拿到一個任務:從PropertyGrid控制項,輸出內容到Word。難點有:
一.PropertyGrid控制項是WinForm控制項,在WPF中並不能直接從工具箱獲得,或者直接在XMAL中聲明使用。
如要使用,需要使用WindowFormHost控制項,再在其內部裝載PropertyGrid控制項。當然前提要在XAML中引用CLR—NAMESAPCE的SYSTEM.WINDOWS.FORMS命名空間。詳細請看此處鏈接:http://www.cnblogs.com/zhuqil/archive/2010/09/02/Wpf-PropertyGrid-Demo.html
二.項目中的PropertyGrid控制項通過指定屬性SeletedObject綁定對應的類,從而顯示類中的屬性,不能直接從控制項中獲取控制項內容。
WPF作為一種聲稱直接操作數據的開發方式,充斥著各式綁定,用戶對UI的操作實際上是對底層數據的操作。如此,我們要獲取屬性內容,就必須要直接從控制項綁定的類中去獲取。在這個項目中,PropertyGrid控制項隨著用戶點擊TreeView上不同的節點,不斷切換指定其SelectedObject屬性綁定節點Item(其實就是綁定節點所綁定的數據類)。
private void trvAllCheckItems_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e) { if (trvAllCheckItems.SelectedItem is ICheckItemGroup || trvAllCheckItems.SelectedItem is ICheckItem) { m_PropertyGrid.SelectedObject = trvAllCheckItems.SelectedItem; } else { TreeViewItem trvi = trvAllCheckItems.SelectedItem as TreeViewItem; if (trvi != null) { m_PropertyGrid.SelectedObject = trvi.Tag; } } }
不同級別的TreeViewItem,綁定不同的類,在底層代碼中,類對我們是可知的。那麼最簡單的方法是直接m_PropertyGrid.SelectedObject is XX(類)判斷是哪個類,然後再as轉換,根據每個類的屬性去獲取值來輸出。但這樣做無疑是簡單粗暴,雖然可行,但太過死板。作為初級開發人員,我還是想寫一些通用性更高的方法。
假設,我不知道PropertyGrid控制項綁定的對象是哪種類,其對象是動態的,未知的,那麼如何獲得綁定對象的屬性(Property)值和屬性特性(Attribute)呢?註:某些特定的特性會影響PropertyGrid控制項的顯示效果,如:System.ComponentModel.BrowsableAttribute。詳細請看此處鏈接:http://blog.csdn.net/luyifeiniu/article/details/5426960
從網上搜了一種方法,使用Type.GetProperties()可以獲取某一類型的屬性信息集合,而遍歷得到每個屬性信息通過PropertyInfo.GetCustomAttributes(true)又可以獲得此屬性的特性。通過這種方法,我們可以得到此對象類型的每個屬性名以及每個屬性上的每個特性信息。那麼如何獲取此時對象的某個屬性的值呢?
很簡單,通過獲取的ProperInfo.GetValue(object 此對象,null)方法,代碼如下:
if (m_PropertyGrid == null || m_PropertyGrid.SelectedObject == null) return; object SelecteObject = m_PropertyGrid.SelectedObject; Type t = SelecteObject.GetType(); DataSet ds = new DataSet(); string m_SaveCheckSchemaPath = ""; //有Category特性標記 bool IsHaveCategory = false; //不創建DataTable標記,初始值為創建 bool IsNotCreateDT = false; //遍歷屬性,每種Category特性創建一個DataTable foreach (PropertyInfo ProInfo in t.GetProperties()) { System.ComponentModel.BrowsableAttribute m_BrowsableAttribute = null; System.ComponentModel.CategoryAttribute m_CategoryAttribute = null; System.ComponentModel.DisplayNameAttribute m_DisplayNameAttribute = null; foreach (Attribute a in ProInfo.GetCustomAttributes(true)) { if (a is System.ComponentModel.BrowsableAttribute) m_BrowsableAttribute = (System.ComponentModel.BrowsableAttribute)a; if (a is System.ComponentModel.CategoryAttribute) m_CategoryAttribute = (System.ComponentModel.CategoryAttribute)a; if (a is System.ComponentModel.DisplayNameAttribute) m_DisplayNameAttribute = (System.ComponentModel.DisplayNameAttribute)a; } if (m_BrowsableAttribute != null && m_BrowsableAttribute.Browsable == false) continue;//屬性不可見,則跳過此項 if (m_CategoryAttribute != null) { //有Category特性標記 IsHaveCategory = true; foreach (DataTable dt in ds.Tables) { if (dt.Columns[0].ColumnName == m_CategoryAttribute.Category) { DataRow row = dt.NewRow(); if (m_DisplayNameAttribute == null) row[m_CategoryAttribute.Category] = ProInfo.Name; else row[m_CategoryAttribute.Category] = m_DisplayNameAttribute.DisplayName; row[1] = ProInfo.GetValue(SelecteObject, null); dt.Rows.Add(row); //已存在的類型表,則標記為不創建 IsNotCreateDT = true; } } if (IsNotCreateDT) { IsNotCreateDT = false; IsHaveCategory = false; continue;//不創建新表,則跳過後續操作 } DataTable DT = new DataTable(); DT.Columns.Add(m_CategoryAttribute.Category, typeof(string)); DT.Columns.Add("", typeof(string)); DataRow Row = DT.NewRow(); if (m_DisplayNameAttribute == null) Row[m_CategoryAttribute.Category] = ProInfo.Name; else Row[m_CategoryAttribute.Category] = m_DisplayNameAttribute.DisplayName; Row[1] = ProInfo.GetValue(SelecteObject, null); DT.Rows.Add(Row); ds.Tables.Add(DT); } //如果此屬性沒有CategoryAttribute,則為雜項類型 if (!IsHaveCategory) { foreach (DataTable dt in ds.Tables) { if (dt.Columns[0].ColumnName == "雜項") { DataRow row = dt.NewRow(); if (m_DisplayNameAttribute == null) row["雜項"] = ProInfo.Name; else row["雜項"] = m_DisplayNameAttribute.DisplayName; row[1] = ProInfo.GetValue(SelecteObject, null); dt.Rows.Add(row); //已存在的類型表,則標記為不創建 IsNotCreateDT = true; } } if (IsNotCreateDT) { IsNotCreateDT = false; continue;//不創建新表,則跳過後續操作 } DataTable DT = new DataTable(); DT.Columns.Add("雜項", typeof(string)); DT.Columns.Add("", typeof(string)); DataRow Row = DT.NewRow(); if (m_DisplayNameAttribute == null) Row["雜項"] = ProInfo.Name; else Row["雜項"] = m_DisplayNameAttribute.DisplayName; Row[1] = ProInfo.GetValue(SelecteObject, null); DT.Rows.Add(Row); ds.Tables.Add(DT); } IsHaveCategory = false; }View Code
寫的可能不是很簡潔,嵌套很多,但已經是改良版了,天知道我之前寫得有多麻煩!整個代碼的目的是把未知的綁定類根據其屬性分類,每個類別創建一個DataTable,存入此類的屬性,最後都加到DataSet里。再之後,我們會輸出這個DataSet的每張表到Word中。