我们知道默认的属性一般都是下拉输入之类的,也有多选,但是我需要的是checkbox,没有现成的,百度发现微软有提供接口UITypeEditor ,继承这个基类就可以搞定了。废话不多说了,下面来具体代码说明。
首先来一段官方资料:
UITypeEditor 类 提供可用于设计值编辑器的基类,这些编辑器可提供用户界面(UI),用来表示和编辑所支持的数据类型的对象值。
UITypeEditor类提供了一个基类,您可以从其派生或将其扩展,来为设计时环境实现一个自定义类型编辑器。通常,您的自定义类型编辑器与 PropertyGrid 控件进行交互。
在文本框值编辑器不足以有效地选择某些类型的值的情况下,自定义类型编辑器非常有用。
若要实现自定义设计时 UI 类型编辑器,必须执行下列步骤:
定义一个从 UITypeEditor 派生的类。
重写 EditValue 方法以处理用户界面、用户输入操作以及值的分配。
重写 GetEditStyle 方法,以便将编辑器将使用的编辑器样式的类型通知给“属性”窗口。
一、引用
using System;
using System.ComponentModel;
using System.ComponentModel.Design.Serialization;
using System.Drawing.Design;
using System.Globalization;
using System.Reflection;
using System.Windows.Forms;
using System.Windows.Forms.Design;
二、源控件及关联的属性
自定义控件[ComboFund]属性
自定义控件的构造函数里面需要实例化这个Fundstatus
_fundType = new FundStatus(); //这个比较重要,最开始的时候这个忘记实例化了,调了半天。
/// <summary>
/// 源控件
/// </summary>
public class ComboFund : Control
{
private FundStatus _FundStatus;
[Editor(typeof(FundStatusEditor),typeof(UITypeEditor))] //属性编辑器接口
[TypeConverter(typeof(FundStatusConverter))] //值转化器
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)] //序列化内容保存设置的值
public FundStatus FundStatus
{
get { return this._FundStatus; }
set { if (this._FundStatus != value) { this._FundStatus = value; } }
}
/// <summary>
/// 【构造函数】在构造控件的时必须属性值初始化
/// </summary>
public ComboFund()
{
_FundStatus = new FundStatus();
}
}
三、属性值的类
public class FundStatus
{
/// <summary>【缓存变量】正常</summary>
private bool _normal = false;
/// <summary>【缓存变量】注销</summary>
private bool _cancel = false;
/// <summary>【缓存变量】冻结</summary>
private bool _frozen = false;
public bool Normal { get { return _normal; } set { _normal = value; } }
public bool Cancel { get { return _cancel; } set { _cancel = value; } }
public bool Frozen { get { return _frozen; } set { _frozen = value; } }
}
四、属性值编辑器的可视化控件
通过执行下列步骤,可以为在“属性”窗口中绘制值的表示形式添加附加支持:
重写 GetPaintValueSupported 方法以指示编辑器支持显示值的表示形式。
重写 PaintValue 方法以实现该值的表示形式的显示。
如果编辑器应具有初始化行为,则重写 UITypeEditor 构造函数方法。
下面是checkbox属性下拉框的例子:
public partial class PropertyFundStatus : UserControl
{
private bool canceling;
private FundStatus _oldfundstatus;
private FundStatus _newfundstatus;
private CheckBox hscb_normal;
private CheckBox hscb_Frozen;
private CheckBox hscb_Cancel;
public PropertyFundStatus(FundStatus fundstatus)
{
_oldfundstatus = fundstatus;
_newfundstatus = fundstatus;
}
public FundStatus FundStatus
{ get { return _newfundstatus; } }
protected override bool ProcessDialogKey(Keys keyData) //重写键盘接收处理ESC
{
if (keyData == Keys.Escape)
{
_oldfundstatus = _newfundstatus;
canceling = true;
}
return base.ProcessDialogKey(keyData);
}
// 离开控件保存值
private void PropertyFundStatus_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 void PropertyFundStatus_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;
}
}
-
五、类别转换器(值转化器)
注意到TypeConverter(typeof(FundStatusConverter))这个特性
public class FundStatusConverter : TypeConverter
{
/// <summary>
/// 是否能用string转换到fundstatus类型。
/// </summary>
/// <param name="context"></param>
/// <param name="sourceType"></param>
/// <returns></returns>
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
{
if (sourceType == typeof(String)) return true;
//这里也可以是其它类型的,可以参考后面的链接里面有介绍
return base.CanConvertFrom(context, sourceType);
}
/// <summary>
/// 能否从fundstatus转换到string。
/// </summary>
/// <param name="context"></param>
/// <param name="destinationType"></param>
/// <returns></returns>
public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
{
if (destinationType == typeof(FundStatus)) return true;
// if (destinationType ==typeof(InstanceDescriptor)) return true;
return base.CanConvertTo(context, destinationType);
}
/// <summary>
/// 从string转到 Fundstatus 类型。在Property窗口中显示为string类型。
/// </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)
{
String result = "";
if (value == null) return result;
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 });
}
return base.ConvertTo(context, culture, value, destinationType);
}
/// <summary>
/// 从 fundstatus转换为string
/// </summary>
/// <param name="context"></param>
/// <param name="culture"></param>
/// <param name="value"></param>
/// <returns></returns>
public override object ConvertFrom(ITypeDescriptorContext context, 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;
}
return base.ConvertFrom(context, culture, value);
}
}
六、源控件属性和属性编辑器关联类
public class FundStatusEditor : UITypeEditor
{
[System.Security.Permissions.PermissionSet(System.Security.Permissions.SecurityAction.Demand)]
public override UITypeEditorEditStyle GetEditStyle(ITypeDescriptorContext context)
{
if (context != null && context.Instance != null)
{
//这里设置下拉模式,还有弹出框的模式
return UITypeEditorEditStyle.DropDown;
}
return base.GetEditStyle(context);
}
[System.Security.Permissions.PermissionSet(System.Security.Permissions.SecurityAction.Demand)]
public override object EditValue(System.ComponentModel.ITypeDescriptorContext context, System.IServiceProvider provider, object value)
{
IWindowsFormsEditorService editorService = null;
if (context != null && context.Instance != null && provider != null)
{
editorService = (IWindowsFormsEditorService)provider.GetService(typeof(IWindowsFormsEditorService));
if (editorService != null)
{
// ComboFund 自定义控件
ComboFund control = (ComboFund)context.Instance;
PropertyFundStatus pfs = new PropertyFundStatus(control.FundStatus);
editorService.DropDownControl(pfs);
value = pfs.FundStatus;
return value;
}
}
return value;
}
}
七、运行结果
参考资料
UITypeEditor 类 (System.Drawing.Design) | Microsoft Learn