彩票走势图

初识用户控件中复杂属性的设计时支持

转帖|其它|编辑:郝浩|2010-12-01 13:49:13.000|阅读 615 次

概述:在设计用户控件的时候(不管是winform还是webform),对于一般的简单属性(string,int,bool……基元类型)系统会为我们自动提供相应的类型转换。本文主要介绍用户控件中复杂属性的设计时支持

# 慧都年终大促·界面/图表报表/文档/IDE等千款热门软控件火热促销中 >>

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

  public int Age
{
get;
set;
}

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

  

  这个属性了。我们可以随便为其设置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属性是灰色的

  

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

  

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

  实现类型转换器

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

  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的设计时的样子,这样就和我们需求的一样了。

  

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

  

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

  实现模态属性编辑器

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

  

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

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

   

  该窗体的后台代码如下:

  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类,其代码如下:

  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(CategoryModalEditor), typeof(UITypeEditor))]
public Person Person
{
get { return person; }
set { person = value; }
}

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

  


 


标签:

本站文章除注明转载外,均为本站原创或翻译。欢迎任何形式的转载,但请务必注明出处、不得修改原文相关链接,如果存在内容上的异议请邮件反馈至chenjj@pclwef.cn

文章转载自:博客转载

为你推荐

  • 推荐视频
  • 推荐活动
  • 推荐产品
  • 推荐文章
  • 慧都慧问
扫码咨询


添加微信 立即咨询

电话咨询

客服热线
023-68661681

TOP