• PropertyGrid使用总结2 TypeConverter


    类型转换的作用,是实现PropertyGrid输入的多个文本信息,能够与对象进行有效的转化,比如我们具有如下一个对象:

    using System; 
    using System.Collections.Generic; 
    using System.ComponentModel; 
    using System.Drawing; 
    using System.Linq; 
    using System.Text; 
    using System.Threading.Tasks; 
    using System.Windows.Forms; 
     
    namespace AlbertControlExample.Controls 
    { 
    /// <summary>
    /// 定义一个新控件
    /// </summary>
    public class AlbertControlDef : Control 
    { 
    public OffsetDef offsetDef 
    { 
     
    get; set; 
    } = new OffsetDef(0,0); 
    public AlbertControlDef() 
    { 
    } 
     
    protected override void OnPaint(PaintEventArgs e) 
    { 
    base.OnPaint(e); 
    } 
    } 
     
    /// <summary>
    /// 定义一个左边偏移
    /// </summary>
    public class OffsetDef{ 
     
    public OffsetDef(int left, int top) 
    { 
    this.Left = left; 
    this.Top = top; 
    } 
     
    public double Left { get; set; } 
    public double Top { get; set; } 
    } 
    } 

    我们看一下显示当前的控件,会发现OffsetDef并不会显示属性,且无法编辑,如图:

    这是由于系统并无法解析OffsetDef对象,意思无法将它转化为可以描述的文本集合,就不能对当前对象进行描述,那我们就需要利用TypeConverter对象,其可以定义如下:

    using System; 
    using System.Collections.Generic; 
    using System.ComponentModel; 
    using System.Drawing; 
    using System.Linq; 
    using System.Text; 
    using System.Threading.Tasks; 
    using System.Windows.Forms; 
     
    namespace AlbertControlExample.Controls 
    { 
    /// <summary>
    /// 定义一个新控件
    /// </summary>
    public class AlbertControlDef : Control 
    { 
    [TypeConverter(typeof(OffsetConverterDef))] 
    public OffsetDef offsetDef 
    { 
    get; set; 
    } = new OffsetDef(100,100); 
    public AlbertControlDef() 
    { 
    } 
     
    protected override void OnPaint(PaintEventArgs e) 
    { 
    base.OnPaint(e); 
    } 
    } 
     
    /// <summary>
    /// 定义一个左边偏移
    /// </summary>
    public class OffsetDef{ 
     
    public OffsetDef(int left, int top) 
    { 
    this.Left = left; 
    this.Top = top; 
    } 
     
    public double Left { get; set; } 
    public double Top { get; set; } 
    } 
     
    public class OffsetConverterDef : TypeConverter { 
     
    /// <summary>
    /// 是否支持属性显示
    /// </summary>
    /// <param name="context"></param>
    /// <returns></returns>
    public override bool GetPropertiesSupported(ITypeDescriptorContext context) 
    { 
    return true; 
    } 
     
    /// <summary>
    /// 返回属性文本的集合定义
    /// </summary>
    /// <param name="context"></param>
    /// <param name="value"></param>
    /// <param name="attributes"></param>
    /// <returns></returns>
    public override PropertyDescriptorCollection GetProperties(ITypeDescriptorContext context, object value, Attribute[] attributes) 
    { 
    var properties= TypeDescriptor.GetProperties(value); 
    return properties; 
    } 
    } 
    } 

    通过返回属性集合,系统会默认显示属性到窗体,其显示结果如下:

    TypeDescriptor肯定不止这么简单,其有几个重要的函数,可以实现对象和输入框之间的互相转换,下面分别说明集合函数的功能和作用

    /// <summary>
    /// 能否将对象转换为字符串
    /// </summary>
    /// <param name="context"></param>
    /// <param name="destinationType"></param>
    /// <returns></returns>
    public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) 
    { 
    return true; 
    } 
     
    /// <summary>
    /// 主要把对象转化为指定的字符串
    /// </summary>
    /// <param name="context"></param>
    /// <param name="culture"></param>
    /// <param name="value"></param>
    /// <param name="destinationType"></param>
    /// <returns></returns>
    public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) 
    { 
    if (value.GetType() == typeof(OffsetDef)) 
    { 
    OffsetDef offsetDef = value as OffsetDef; 
    return string.Format("{0},{1}",offsetDef.Left, offsetDef.Top); 
     
    } 
    return base.ConvertTo(context, culture, value, destinationType); 
    } 

    其显示会如下:

    当前定义是将对象转化为字符串对象,并且显示在当前对象对应的文本框之中。以上界面,我们通过修改100,100这个文本框是无法修改的,它只能转换过来,假如我们想可以编辑他,并且自动转换为对象,可以实现如下几个函数:

    /// <summary>
    /// 是否能从文本转化为对象
    /// </summary>
    /// <param name="context"></param>
    /// <param name="sourceType"></param>
    /// <returns></returns>
    public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) 
    { 
    return true; 
    } 
     
    public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) 
    { 
    if (value.GetType() == typeof(string)) { 
    string objDec = value.ToString(); 
     
    string[] vsp = objDec.Split(','); 
     
    if (vsp.Length == 2) { 
     
    OffsetDef offsetDef = new OffsetDef(int.Parse(vsp[0]),int.Parse(vsp[1])); 
    return offsetDef; 
    } 
     
    } 
    return base.ConvertFrom(context, culture, value); 
     
     
    } 

    通过以上的定义,我们发现,现在修改100,100这个文本框的内容,对象的属性定义会自动改变,那是因为只要修改对象所对应的文本框,就会调用ConvertFrom函数,将当前文本框的内容自动转化为对象,但是不能输入错误的值,比如输入一个无法转换为int的字符串,那么就会报错。其结果显示如下:

    但是其发现另外一个问题,我们修改100,100为100,200是否,那么对应的left和top的值会自动变化,但是我们修改Left/top的值的时候,并没有影响到offsetDef的值,那是因为修改left op不会触发ConvertFrom函数,所以以上的转化就会出问题,那我们怎么解决这个问题呢,则需要实现TypeDescriptor另外两个函数:

    /// <summary>
    /// 是否能重新创建对象,默认是不创建,当前是需要创建的,所以我们直接返回true
    /// </summary>
    /// <param name="context"></param>
    /// <returns></returns>
    public override bool GetCreateInstanceSupported(ITypeDescriptorContext context) 
    { 
    return true; 
    } 
     
    /// <summary>
    /// 返回创建的实例对象,这个函数的调用,只要当前属性列表发生变化,当前函数都会启动调用,也会返回当前所有的属性列表
    /// </summary>
    /// <param name="context"></param>
    /// <param name="propertyValues"></param>
    /// <returns></returns>
    public override object CreateInstance(ITypeDescriptorContext context, IDictionary propertyValues) 
    { 
    if (propertyValues.Count == 2) { 
     
    OffsetDef def = new OffsetDef(int.Parse(propertyValues["Left"].ToString()), int.Parse(propertyValues["Top"].ToString())); 
    return def; 
    } 
    return base.CreateInstance(context, propertyValues); 
    } 

    通过以上两个函数,你会发现,修改任何属性对应的文本,那么这个对象就会重新定义,对象也会跟着改变。这个对象不仅仅有这些功能,其还有几个非常重要的函数。

    public override bool GetStandardValuesSupported(ITypeDescriptorContext context) 
    { 
    return true; 
    } 
     
    public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext context) 
    { 
    StandardValuesCollection standardValues = new StandardValuesCollection(new string[]{ "100,200","200,300","400,500"}); 
    return standardValues; 
    } 

    通过以上函数,可以对当前的对象指定一个标准的值,供用户下拉选择,通过以上的代码,则可以实现如下功能:

    同时还有其他几个函数,这里就不一一说明,通过TypeConverter的定义,我们可以实现属性文本列表和对象的互相转换,实现对象的可配置。当前对象还有一个很重要的特性没有说明,就是attributes和CultureInfo,ITypeDescriptorContext三个对象:

    1. attributes对象当然是对每个Property属性上的attribute获取和进行访问的列表
    2. CultureInfo 主要用于实现控件的国际化的定义
    3. ITypeDescriptorContext 主要是当前类型标识的上下文信息,当前类型定义并没有指定TypeDescriptor对象,所以当前对象为空,我们在接下来的章节,会介绍此对象。
  • 相关阅读:
    编码
    浏览器翻页
    验证码识别
    时间
    phantomjs配置
    产品
    java范型的理解
    使用JDBC连接数据库
    垃圾回收机制
    java的内存区域 && java内存模型
  • 原文地址:https://www.cnblogs.com/minhost/p/12297091.html
Copyright © 2020-2023  润新知