.Net 用户控件中复杂属性的设计时支持

本文介绍如何通过自定义类型转换器和模态属性编辑器,实现用户控件中复杂属性的设计时友好设置。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

http://blog.163.com/prince.king_521/blog/static/10689120420101019963625/


引入

  在设计用户控件的时候(不管是winform还是webform),对于一般的简单属性(string,int,bool……基元类型)系统会为我们自动提供相应的类型转换。举个例子:我们在用户控件中定义一个Age属性,

        public int Age         {             get;             set;         }

这时我们打开设计器,就会看到

2010-11-18_200106

这个属性了。我们可以随便为其设置int类型的值。但是当我们试着填写一个string类型的字符时,系统就会弹出一个“属性无效”窗口,在这个过程中我们就可以看出系统已经为Age做了类型转换,而且这个转换失败了,因为类型不匹配。

     

     现在让我们再写一个复杂点的属性Person。先创建一个Person类,它里面包含了name和age属性:

    public class Person     {         private string strName;         private int intAge;          public string StrName         {             get { return strName; }             set { strName = value; }         }          public int IntAge         {             get { return intAge; }             set { intAge = value; }         }     }

然后在用户控件中,我们新建一个person的属性:

        private Person person;          public Person Person         {             get { return person; }             set { person = value; }         }

打开设计器窗体后我们可以看到Person属性是灰色的

2010-11-18_201553 

为什么会这样呢?答案很简单,系统不知道如何去显示这个属性。但总得显示点儿什么吧?于是无可奈何下显示了person类的类型名。这与我们所期望的形如Location样式的可差远了

2010-11-18_202006

到底差在哪里呢?类型转换器!当我们在Person里面填写"zhangsan,21"的时候,类型转换器就能自动将这两个属性值对应到strName,intAge上面去,这就是类型转换器的作用。那么下面我们就来实现一个person的类型转换器。

 

实现类型转换器

       首先新建一个新类PersonConverter,用于提供person类型转换的能力,所有的注释我都写在代码里面了,大家一看就明白:

 

.Net 用户控件中复杂属性的设计时支持 (转) - 恋上你的床 - ……     public class PersonConverter:TypeConverter     {         //指示我们设置的内容能否转换         //因为我们输入的是“zhangsan,12”的字符串形式,所以这里接受字符串类型的转换         public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)         {             return sourceType == typeof(string) || base.CanConvertFrom(context, sourceType);         }          //这个方法指示了最后的这个复杂属性是以什么形式表现出来的。         //如果destinationType == typeof(string)的话,最后person显示的就是"zhangsan,21"的形式         //如果destinationType == typeof(InstanceDescriptor)的话,person显示的就是"WindowsFormsControlLibrary1.Person"类名的形式。         public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)         {             if (destinationType == typeof(string))             {                 return true;             }              if (destinationType == typeof(InstanceDescriptor))             {                 return true;             }              return base.CanConvertTo(context, destinationType);         }          //这个方法实现了我们输入的字符串如何被转化为person类型         public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value)         {             if (value is string)             {                 String[] v = ((String)value).Split(',');                 if (v.GetLength(0) != 2)                 {                     throw new ArgumentException("Invalid parameter format");                 }                  Person csf = new Person { Name = Convert.ToString(v[0]), Age = Convert.ToInt32(v[1]) };                 return csf;             }             return base.ConvertFrom(context, culture, value);         }          //这个则是实现了具体如何显示person这个属性的方法         public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType)         {             if (destinationType == typeof(String))             {                 Person scope = (Person)value;                 String result = scope.Name.ToString() + "," + scope.Age.ToString();                 return result;             }              if (destinationType == typeof(InstanceDescriptor))             {                 ConstructorInfo ci = typeof(Person).GetConstructor(new Type[] { typeof(string), typeof(Int32) });                 Person scope = (Person)value;                 return new InstanceDescriptor(ci, new object[] { scope.Name, scope.Age });             }             return base.ConvertTo(context, culture, value, destinationType);         }          //以下两个方法提供子属性单独设置的能力。         public override bool GetPropertiesSupported(ITypeDescriptorContext context)         {             return true;         }          public override PropertyDescriptorCollection GetProperties(ITypeDescriptorContext context, object value, Attribute[] attributes)         {             return TypeDescriptor.GetProperties(typeof(Person), attributes);         }      }

 

 

然后在用户控件的person属性上加上这么一句,指定了person的转换器:

        [TypeConverter(typeof(PersonConverter))]         public Person Person         {             get;             set;         }

我们现在再来看看person的设计时的样子,这样就和我们需求的一样了。

2010-11-18_205722

这里再教大家一个偷懒的方法,就是实现转换器的时候不必重写最上面的那四个方法,直接重写“提供子属性单独设置的能力”的两个方法就是了。只不过这样person属性显示的效果如下:

2010-11-18_210443

就是person显示的内容变了,子属性还是提供设置。对于要求不高的属性也够了。

 

实现模态属性编辑器

      前面我们实现了形如Location属性的设计时属性设置支持,但我们有时需要的可能不只是这么复杂的属性设置。比如BackgroundImage这个属性,当我们设置它的时候,系统会弹出一个界面出来让我们选择图片:

2010-11-18_211529

使用这种方式无疑增加了我们选择图片的方便度。那这种形式的设置该如何实现呢?

     首先我们新建一个窗体,这个窗体就是将来需要显示给用户设置属性的(比如上图的“选择资源”窗体)。我们还是以person类为例:

2010-11-18_212737

该窗体的后台代码如下:

 

.Net 用户控件中复杂属性的设计时支持 (转) - 恋上你的床 - ……         private Person _person;          public PersonWindow(Person person)         {             InitializeComponent();              Person = person;              textBox1.Text = person.StrName;             textBox2.Text = person.IntAge.ToString();         }          public Person Person         {             get { return _person; }             set { _person = value; }         }          /// <summary>         /// 确认按钮         /// </summary>         /// <param name="sender"></param>         /// <param name="e"></param>         private void button1_Click(object sender, EventArgs e)         {             Person.StrName = textBox1.Text;             Person.IntAge = int.Parse(textBox2.Text);         }  

 

这里要注意的一点就是confirm按钮的DialogResult要设置为DialogResult.OK,cancel按钮的DialogResult要设置为DialogResult.Cancel。至于为什么要这么做大家往后看就知道了。

      然后我们再建立一个class PersonModalEditor:System.Drawing.Design.UITypeEditor类,其代码如下:

.Net 用户控件中复杂属性的设计时支持 (转) - 恋上你的床 - ……         public override System.Drawing.Design.UITypeEditorEditStyle GetEditStyle(System.ComponentModel.ITypeDescriptorContext context)         {             //指示以什么样的形式打开编辑窗体             return UITypeEditorEditStyle.Modal;         }          //属性编辑方法,当我们单击属性窗口中的属性按钮时会执行这个方法。         public override object EditValue(System.ComponentModel.ITypeDescriptorContext context, IServiceProvider provider, object value)         {             //获取服务对象,这个对象专门为winform编辑器提供一些功能             IWindowsFormsEditorService service =                 (IWindowsFormsEditorService) provider.GetService(typeof (IWindowsFormsEditorService));              if (service==null)             {                 return null;             }              Person p = new Person();             CategoryWindow form = new CategoryWindow(p);              //这里知道为什么要设置confirm按钮的DialogResult属性的原因了吧。             if (service.ShowDialog(form) == System.Windows.Forms.DialogResult.OK)             {                 return p;             }              return value; //系统会根据这个返回值在person属性里面进行填充         } 

 

最后我们在用户控件的person属性上加上这个一句话:

        [Editor(typeof( PersonModalEditor), typeof(UITypeEditor))]         public Person Person         {             get { return person; }             set { person = value; }         }

这句话指定了系统如何打开person的属性编辑器。我们看看效果图:

 2010-11-18_214343


 

作者: 钱李峰
出处: http://qianlifeng.cnblogs.com
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,否则保留追究法律责任的权利。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值