C#組件編程(2)
較复雜的屬性為了編輯方便,就要用到屬性編輯器.
由于在屬性視窗中只能識別字符串類型,如果是非字符串類型的屬性還需要用到類型轉換器.
下面就分別講它們的使用方法:
1.屬性編輯器Property Editor
在vs环境中Property Editor有两种,一种是vs自带的,一种是Component编写者根据自己需求而重新编写的。
示例:
using System;
using System.Collections.Generic;
using System.Collections;
using System.Text;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Drawing;
using System.Drawing.Design;
using System.Windows.Forms;
using System.Windows.Forms.Design;
namespace Components
{
// 这个例子用到了vs 2005里的List<>.
public class Demo3 : Component
{
public Demo3()
{
_students = new List<Student>(); // 一定要在构造函数中实例化_students。
}
private List<Student> _students;
private string _grade;
// 使用 vs自带的Editor。
// 如果没有DesignerSerializationVisibilityAttribute的话,对Students设值,值不能被保存。
// 大家可以把DesignerSerializationVisibilityAttribute注释掉,对Students设值后,关闭vs环境,再重新打开项目,观察Students的值没有被保存下来。
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
public List<Student> Students
{
get { return _students; }
set { _students = value; }
}
//使用用户自定义的Editor。
[Editor(typeof(GradeEditor), typeof(UITypeEditor)), LocalizableAttribute(true)]
public string Grade
{
get { return _grade; }
set { _grade = value; }
}
}
public class Student
{
private int _id;
private string _name;
public int Id
{
get { return _id; }
set { _id = value; }
}
public string Name
{
get { return _name; }
set { _name = value; }
}
}
/*//在vs2003中實現集合的方式,這比在vs2005中使用泛型复雜多了.
public class StudentCollection : CollectionBase,IList
{
public Student this[int index]
{
get { return (Student)(List[index]); }
set { List[index] = value; }
}
public int Add(Student value)
{
return List.Add(value);
}
public int IndexOf(Student value)
{
return List.IndexOf(value);
}
public bool Contains(Student value)
{
return List.Contains(value);
}
public void Remove(Student value)
{
List.Remove(value);
}
} */
public class GradeEditor : UITypeEditor
{
[System.Security.Permissions.PermissionSet(System.Security.Permissions.SecurityAction.Demand)]
public override System.Drawing.Design.UITypeEditorEditStyle GetEditStyle(System.ComponentModel.ITypeDescriptorContext context)
{
// UITypeEditorEditStyle有三种,Modal是弹出式,DropDown是下拉式,None是没有。
return UITypeEditorEditStyle.Modal;
}
[System.Security.Permissions.PermissionSet(System.Security.Permissions.SecurityAction.Demand)]
public override object EditValue(System.ComponentModel.ITypeDescriptorContext context, System.IServiceProvider provider, object value)
{
// 得到editor service,可由其创建弹出窗口。
IWindowsFormsEditorService editorService = (IWindowsFormsEditorService)provider.GetService(typeof(IWindowsFormsEditorService));
// context.Instance —— 可以得到当前的Demo3对象。
// ((Demo3)context.Instance).Grade —— 可以得到当前Grade的值。
frmGradeEditor dialog = new frmGradeEditor();
editorService.ShowDialog(dialog);
String grade = dialog.Grade;
dialog.Dispose();
return grade;
}
}
}
2.TypeConverterAttribute(类型转换)
示例:
using System;
using System.Collections.Generic;
using System.Text;
using System.ComponentModel;
using System.Globalization;
namespace ClassLibrary1
{
public class Class1 : Component
{
private Size _size;
public Class1()
{
_size = new Size();
}
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
[TypeConverter(typeof(SizeConverter))] // —— 注1,也可以把这句TypeConverterAttribute写在注2处。
public Size Size
{
get { return _size; }
set { _size = value; }
}
}
public class SizeConverter : TypeConverter // 我们自定义的Converter必须继承于TypeConverter基类。
{
/// <summary>
/// 是否能用string转换到Size类型。
/// </summary>
/// <param name="context">上下文。</param>
/// <param name="sourceType">转换源的Type。</param>
/// <returns></returns>
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
{
if (sourceType == typeof(string))
{ return true; }
else
{ return false; }
}
/// <summary>
/// 从string转到Size类型。
/// </summary>
/// <param name="context">提供Component的上下文,如Component.Instance对象等。</param>
/// <param name="culture">提供区域信息,如语言、时间格式、货币格式等</param>
/// <param name="value"></param>
/// <returns></returns>
public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value)
{
if (value == null || value.ToString().Length == 0) return new Size();
char spliter = culture.TextInfo.ListSeparator[0]; // 得到字符串的分隔符
string[] ss = ((string)value).Split(spliter);
Int32Converter intConverter = new Int32Converter(); // 得到类型转换器,.net中为我们定义了一些常见的类型转换器。
return new Size((Int32)intConverter.ConvertFromString(context, culture, ss[0]),
(Int32)intConverter.ConvertFromString(context, culture, ss[1]));
}
/**//// <summary>
/// 是否能用Size转换到string类型。
/// </summary>
/// <param name="context"></param>
/// <param name="destinationType">转换目标的类型。</param>
/// <returns></returns>
public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
{
if (destinationType == typeof(Size)) // 如果是Size格式,则允许转成string。
{ return true; }
else
{ return false; }
}
// 在Property窗口中显示为string类型。
public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType)
{
if (value == null) return string.Empty;
if (destinationType == typeof(string))
{
Size size = (Size)value;
TypeConverter intConverter = TypeDescriptor.GetConverter(typeof(Int32)); // 得到类型转换器的另一种方式。
char spliter = culture.TextInfo.ListSeparator[0]; // 得到字符串的分隔符
return string.Join(spliter.ToString(), new string[]{
intConverter.ConvertToString(context, culture, size.Length),
intConverter.ConvertToString(context, culture, size.Width)});
}
return string.Empty;
}
// TypeConverter还有几个虚方法,请大家自己研究。
}
// [TypeConverter(typeof(SizeConverter))] —— 注2
public class Size
{
private Int32 _length;
private Int32 _width;
public Size(Int32 length, Int32 width)
{
_length = length;
_width = width;
}
public Size() : this(0, 0)
{
}
public Int32 Length
{
get { return _length; }
set { _length = value; }
}
public Int32 Width
{
get { return _width; }
set { _width = value; }
}
}
}