您的位置:首页 > 运维架构

如何让DEV PropertyGridControl根据自定义Attribute特性来自定义输入显示

2014-07-02 09:47 661 查看
-------基于Dev13.2.5及以上版本

DevExpress13.2.5 及以上版本PropertyGridControl(WPF版本)这个控件同Visual Studio标准库中的PropertyGrid是同类的,都是用于快速便捷的显示一个类的Property属性,并提供用户输入的功能。具体作用可以参考MSDN,或者DevExpress HelpDocument 13.2.5。
写这个主题,主要是因为近期项目涉及到一个单位配置系统,用户需可以根据自身需要选择公制单位、英制单位以及自定义单位。在配置发生改变之后,UI涉及单位的参数输入部分则需要同步直观的跟着改变。在UI中,所有参数基本是以PropertyGridControl(WPF版本)作为用户输入接口的。
琢磨了一下,解决这个问题,脑子里大致有三种解决方案:
1.       在参数实体类中,在Property的DisplayName附加属性中加上单位,如图



显然,这种方式很不方便,要更改单位岂不是很麻烦,比如将MPa换成Pa?而且看起来也不舒服
2.       改写PropertyGridControl的Template,很显然,单单改写Template还不够,因为它缺乏单位对应的依赖项属性,那么我们需要在数据结构类中添加额外的Property来记录对应的参数的单位,显然,这个就破坏了代码的可重用性,甚至扰乱程序架构,处理数据的部分竟然还需要管UI的死活,这显然不合理。
3.       这种方法也是我采取的方法,则是通过自定义特性,给参数类属性添加单位类别的标记,然后在UI显示的时候根据单位标记来自定义显示,这个对于我们的需求也是比较合理的,也容易维护。
 
下面来具体说明:
首先,我们先模拟一个用户参数输入的类:UserParams
public
class UserParams
    {
        [DisplayName("压力")]
        public
double A { get;
set; }
 
        [DisplayName("深度")]
        public
double B { get;
set; }
 
        [DisplayName("温度")]
        public
double C { get;
set; }
 
        public UserParams()
        {
            A = 1;
            B = 2;
            C = 3;
        }
}
 
 
可以看到,这个类用户需要三个参数,压力(MPa),深度(Km),温度(C)
其次,我们还需要构造一个自定义特性以及一个枚举来标示不同的类别的单位(UserParams类中有三种单位类别,即压力,长度,温度),类UnitTypeAttribute,枚举类型UnitTypes:
///<summary>
    ///单位类型
    ///</summary>
public
enum UnitTypes
    {
        None,//没有单位,如百分比
        A,//A类单位
        B,//B类单位 之后类推       

C,
       D,
        E,
        F,
        G,
        H,
        I,
        J,
        K,
        L,
        M,
    }
 
    [AttributeUsage(AttributeTargets.Property,AllowMultiple =
false,Inherited =
true)]
    public
class UnitTypeAttribute:Attribute
    {
      
        public UnitTypeAttribute(UnitTypes t)
        {
            _unitType = t;
        }
 
       private
UnitTypes _unitType = UnitTypes.None;
 
      
        ///<summary>
        ///单位类型
        ///</summary>
        public
UnitTypes UnitType
        {
            get {
return _unitType; }
            set { _unitType =
value; }
        }
    }
 
在此之后,我们需要拖放一个PropertyGridControl到主界面,并将其SelectedObject属性设置为一个UserParams类实例,基本运行效果如下:
 


 
我们可以看到,现在的数值是看不到它的单位是什么的,现在我们将自定义的UnitTypeAttribute特性添加到UserParams的Property上,然后给PropertyGridControl添加CustomDisplayText事件(这个事件主要是用来自定义用户输入的显示),具体修改如下:
UserParams类:
public
class UserParams
    {
        [DefaultValue(10),
UnitType(UnitTypes.A)]
        [DisplayName("压力")]
        public
double A { get;
set; }
 
        [DisplayName("深度"),UnitType(UnitTypes.B)]
        public
double B { get;
set; }
 
        [DisplayName("温度"),UnitType(UnitTypes.C)]
        public
double C { get;
set; }
 
        public UserParams()
        {
            A = 1;
            B = 2;
            C = 3;
        }
}
 
MainWindow.xaml.cs类:
///<summary>
    /// MainWindow.xaml
的交互逻辑
    ///</summary>
    public
partial class
MainWindow : Window
    {
        private
UserParams userParams;
        public MainWindow()
        {
            InitializeComponent();
            Init();
        }
        void Init()
        {
            userParams =
new UserParams();
            //让PropertyGridControl显示UserParams类的实例
            propertyGridControl.SelectedObject= userParams;
            //添加用户输入数值自定义显示事件
           propertyGridControl.CustomDisplayText +=propertyGridControl_CustomDisplayText;
 
 
        }
 
    
 
        voidpropertyGridControl_Custom
adb9
DisplayText(object sender, DevExpress.Xpf.PropertyGrid.CustomDisplayTextEventArgs
args)
        {
            string text =args.DisplayText;//获取用户输入值
            Type type =propertyGridControl.SelectedObject.GetType();//获取当前PropertyGridControl显示对象类型
            UnitTypes utype =
UnitTypes.None;//用于记录当前属性类型
            PropertyInfo[] info =type.GetProperties();//获取类类型的所有属性
 
            foreach (PropertyInfo i
in info)
            {
                if(i.Name!=args.Row.FullPath)//判断当前属性名称是否和PropertyGridControl处理的一致,不一致,则继续下一个属性
                { continue;}//这里很重要,如果没有这一判断,会出现单位混乱
                var aa =i.GetCustomAttributes(typeof(UnitTypeAttribute),
true);//获取自定义特性
                UnitTypeAttribute d =
new
UnitTypeAttribute(UnitTypes.None);//记录得到的自定义特性
                if(aa.Length>=0&&aa[0]
is
UnitTypeAttribute)
                {
                    d = aa[0]
as UnitTypeAttribute;
                    utype = d.UnitType;
                }
 
                if (utype ==
UnitTypes.None)
continue;//没有单位,或单位为百分比
 
                args.DisplayText =ProcessingUnitTransfer(text, utype);//单位转换系统
 
            }
            //Debug Info
            Console.WriteLine(string.Format("DisplayText={0},Row={1}
,UnitType={2}",args.DisplayText,args.Row.Path,utype));
 
        }
 
 
        stringProcessingUnitTransfer(string text,UnitTypes type)
        {
            //TODO:这里实现单位转换系统,这里只做简单测试
            switch (type)
            {
                case
UnitTypes.A:
                    return
string.Format("{0}   MPa", text);
 
                    case
UnitTypes.B:
                    return
string.Format("{0}   Km", text);
 
                    case
UnitTypes.C:
                    return
string.Format("{0}   C", text);
 
                default:
                    return text;
            }
        }
}
 
最终运行结果:

 


达到所需效果!如释重负有没有~~~主要思路便是获取用户当前配置的类类型,然后根据反射获取类的属性,通过判断属性是否包含我们的自定义特性,来选择是否处理这个属性,如果包含,则判断这个自定义特性的特性值,根据特性值来判断是哪个单位组类别,然后做相应的处理,很简单是不是。。。鼓捣一天出来的结果。。。就是注释里边那个重点部分卡了好久。。。
 
 
 
由于网上基本搜不到此类问题处理信息,因此整理发表供需要的人参考,如果有更好的处理方式,希望能与我交流,联系方式:BenDerPan@163.com转载请标明出处。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐