转自:http://blog.sina.com.cn/s/blog_59cea87f0101g69d.html
最近项目需要用到自定义控件的属性需要多选,我们知道默认的属性一般都是下拉输入之类的,也有多选,但是我需要的是checkbox,没有现成的,百度发现微软有提供接口UITypeEditor
首先来一段官方资料:
UITypeEditor 类 提供可用于设计值编辑器的基类,这些编辑器可提供用户界面(UI),用来表示和编辑所支持的数据类型的对象值。
UITypeEditor类提供了一个基类,您可以从其派生或将其扩展,来为设计时环境实现一个自定义类型编辑器。通常,您的自定义类型编辑器与 PropertyGrid 控件进行交互。
在文本框值编辑器不足以有效地选择某些类型的值的情况下,自定义类型编辑器非常有用。
若要实现自定义设计时 UI 类型编辑器,必须执行下列步骤:
定义一个从 UITypeEditor 派生的类。
重写 EditValue 方法以处理用户界面、用户输入操作以及值的分配。
重写 GetEditStyle 方法,以便将编辑器将使用的编辑器样式的类型通知给“属性”窗口。
通过执行下列步骤,可以为在“属性”窗口中绘制值的表示形式添加附加支持:
重写
重写
-
如果编辑器应具有初始化行为,则重写 UITypeEditor 构造函数方法。 下面是我写的checkbox属性下拉框的例子:
1.
首先建立一个usercontrol 以下是源码 :
public partial classPropertyFundStatus : UserControl { private boolcanceling; private FundStatus_oldfundstatus; private FundStatus_newfundstatus; publicPropertyFundStatus(FundStatus fundstatus) { _oldfundstatus = fundstatus; _newfundstatus = fundstatus; InitializeComponent(); }
public FundStatusFundStatus { get { return _newfundstatus; } }
protected override bool ProcessDialogKey(KeyskeyData) //重写键盘接收处理ESC { if (keyData == Keys.Escape) { _oldfundstatus = _newfundstatus; canceling= true; } returnbase.ProcessDialogKey(keyData); } // 离开控件保存值 private voidPropertyFundStatus_Leave(object sender, EventArgs e) { if (!canceling) { //保存值 if(hscb_normal.Checked) { _newfundstatus.Normal =true; } else { _newfundstatus.Normal =false; } if(hscb_Frozen.Checked) { _newfundstatus.Frozen =true; } else { _newfundstatus.Frozen =false; } if(hscb_Cancel.Checked) { _newfundstatus.Cancel =true; } else { _newfundstatus.Cancel =false; } } } //加载属性控件的时候赋值 private voidPropertyFundStatus_Load(object sender, EventArgs e) { //赋值 hscb_normal.CheckState = _oldfundstatus.Normal ?CheckState.Checked : CheckState.Unchecked; hscb_Frozen.CheckState = _oldfundstatus.Frozen ?CheckState.Checked : CheckState.Unchecked; hscb_Cancel.CheckState = _oldfundstatus.Cancel ?CheckState.Checked : CheckState.Unchecked; } } 2. 这个自定义控件三个选项值保存在FundStatus类中
public class FundStatus{ /// /// 正常 /// private bool _normal =false; /// /// 注销 /// private bool _cancel =false; /// /// 冻结 /// private bool _frozen =false;
public boolNormal { get { return _normal; } set { _normal = value; } } public boolCancel { get { return _cancel; } set { _cancel = value; } } public boolFrozen { get { return _frozen; } set { _frozen = value; } } } 3. 说了这些还没有到说到正题,下面来介绍自定义控件的属性自定义控件[ComboFund]属性 [ Editor(typeof (FundStatusEditor), typeof(UITypeEditor)), //属性编辑器接口 TypeConverter(typeof (FundStatusConverter)), //值转化器 DesignerSerializationVis ibility(DesignerSerializationVis ibility.Content)] //序列化内容保存设置的值 publicFundStatus FundStatus { get { return this._fundType;} set { if (this._fundType != value) { this._fundType = value; this.Reset(); } } } 自定义控件的构造函数里面需要实例化这个Fundstatus_fundType = new FundStatus(); //这个比较重要,最开始的时候这个忘记实例化了,调了半天。
4.注意到TypeConverter(typeof(FundStatusConverter))这个特性public class FundStatusConverter :TypeConverter { /// /// 是否能用string转换到fundstatus类型。 /// publicoverride bool CanConvertFrom(ITypeDescriptorContext context, TypesourceType) { if (sourceType ==typeof(String)) return true; //这里也可以是其它类型的,可以参考后面的链接里面有介绍 returnbase.CanConvertFrom(context, sourceType); } /// ///能否从fundstatus转换到string /// publicoverride bool CanConvertTo(ITypeDescriptorContext context, TypedestinationType) { if (destinationType ==typeof( FundStatus )) returntrue;
// if (destinationType ==typeof(InstanceDescriptor)) return true;
returnbase.CanConvertTo(context, destinationType); }
/// ///从string转到 Fundstatus 类型。在Property窗口中显示为string类型。 /// publicoverride object ConvertTo(ITypeDescriptorContext context,System.Globalization.CultureInfo culture, object value, TypedestinationType) { String result = ""; if (value == null) returnresult; if (destinationType ==typeof(String)) { //这里处理选择后在属性框里面显示的值 FundStatus scope = ( FundStatus )value; if (scope.Normal) { if(result.Length > 0) result += ",normal"; else result += "normal"; } else result =result.Replace("normal", "").Replace(",normal", ""); if (scope.Cancel) { if(result.Length > 0) result += ",cancel"; else result += "cancel"; } else result =result.Replace("cancel", "").Replace(",cancel",""); if (scope.Frozen) { if (result.Length > 0) result += ",frozen"; else result += "frozen"; } else result =result.Replace("frozen", "").Replace(",frozen",""); return result;
}
if (destinationType ==typeof(InstanceDescriptor)) { ConstructorInfo ci =typeof(FundStatus).GetConstructor(new Type[] { typeof(bool),typeof(bool),typeof(bool) }); FundStatus scope = (FundStatus)value; return new InstanceDescriptor(ci, new object[] {scope.Cancel, scope.Frozen,scope.Normal }); } returnbase.ConvertTo(context, culture, value, destinationType); }
/// ///从 fundstatus转换为string /// publicoverride object ConvertFrom(ITypeDescriptorContext context,System.Globalization.CultureInfo culture, object value) { if (value == null ||value.ToString().Length == 0) return new FundStatus(); if (value is string) { //String[] v = ((String)value).Split(','); string tempvalue = (string) value; FundStatus csf = new FundStatus(); csf.Cancel =tempvalue.Contains("cancel"); csf.Frozen =tempvalue.Contains("frozen"); csf.Normal =tempvalue.Contains("normal"); return csf; } returnbase.ConvertFrom(context, culture, value); } 5.说到这里最重要的东西还没有讲,继承基类UITypeEditor的FundStatusEditorpublicclass FundStatusEditor : UITypeEditor { [System.Security.Permissions.PermissionSet(System.Security.Permissions.SecurityAction.Demand)] publicoverride System.Drawing.Design.UITypeEditorEditStyleGetEditStyle(System.ComponentModel.ITypeDescriptorContextcontext) { if (context != null&& context.Instance != null) { //这里设置下拉模式,还有弹出框的模式returnUITypeEditorEditStyle.DropDown; } returnbase.GetEditStyle(context); } [System.Security.Permissions.PermissionSet(System.Security.Permissions.SecurityAction.Demand)] publicoverride objectEditValue(System.ComponentModel.ITypeDescriptorContextcontext, System.IServiceProviderprovider, object value) { IWindowsFormsEditorServi ceeditorService = null; if (context != null&& context.Instance != null&& provider != null) { editorService=(IWindowsFormsEditorServi ce)provider.GetService(typeof(IWindowsFormsEditorServi ce)); if (editorService != null) { // ComboFund 自定义控件ComboFund control = (ComboFund)context.Instance; PropertyFundStatus pfs = newPropertyFundStatus(control.FundStatus); editorService.DropDownControl(pfs); value =pfs.FundStatus; returnvalue; } } return value; } }
6.这些搞完后如下图,这个就是我们要的属性选择,当然我们还可以做成弹出框的样式还有自己想怎么定义样式就怎么定义,非常方便。
参考资料: