zoukankan      html  css  js  c++  java
  • 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对象,所以当前对象为空,我们在接下来的章节,会介绍此对象。
  • 相关阅读:
    算法训练 P1103
    算法训练 表达式计算
    算法训练 表达式计算
    基础练习 时间转换
    基础练习 字符串对比
    Codeforces 527D Clique Problem
    Codeforces 527C Glass Carving
    Codeforces 527B Error Correct System
    Codeforces 527A Glass Carving
    Topcoder SRM 655 DIV1 250 CountryGroupHard
  • 原文地址:https://www.cnblogs.com/minhost/p/12297091.html
Copyright © 2011-2022 走看看