学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; }
写的可能不是很简洁,嵌套很多,但已经是改良版了,天知道我之前写得有多麻烦!整个代码的目的是把未知的绑定类根据其属性分类,每个类别创建一个DataTable,存入此类的属性,最后都加到DataSet里。再之后,我们会输出这个DataSet的每张表到Word中。