C#控件开发---控件属性编辑器

最近项目需要用到自定义控件的属性需要多选,我们知道默认的属性一般都是下拉输入之类的,也有多选,但是我需要的是checkbox,没有现成的,百度发现微软有提供接口UITypeEditor ,继承这个基类就可以搞定了。废话不多说 了,下面来具体代码说明。
首先来一段官方资料:
UITypeEditor 类 提供可用于设计值编辑器的基类,这些编辑器可提供用户界面 (UI),用来表示和编辑所支持的数据类型的对象值。 
UITypeEditor 类提供了一个基类,您可以从其派生或将其扩展,来为设计时环境实现一个自定义类型编辑器。通常,您的自定义类型编辑器与 PropertyGrid 控件进行交互。 
在文本框值编辑器不足以有效地选择某些类型的值的情况下,自定义类型编辑器非常有用。
若要实现自定义设计时 UI 类型编辑器,必须执行下列步骤:
定义一个从 UITypeEditor 派生的类。
重写 EditValue 方法以处理用户界面、用户输入操作以及值的分配。
重写 GetEditStyle 方法,以便将编辑器将使用的编辑器样式的类型通知给“属性”窗口。
 

通过执行下列步骤,可以为在“属性”窗口中绘制值的表示形式添加附加支持:

重写 GetPaintValueSupported 方法以指示编辑器支持显示值的表示形式。

重写 PaintValue 方法以实现该值的表示形式的显示。

  •  如果编辑器应具有初始化行为,则重写 UITypeEditor 构造函数方法。

    下面是我写的checkbox属性下拉框的例子:

    1.  首先建立一个usercontrol

    C#控件开发---控件属性编辑器

    以下是源码 :

     public partial class PropertyFundStatus : UserControl
        {
            private bool canceling;
            private FundStatus _oldfundstatus;
            private FundStatus _newfundstatus;
            public PropertyFundStatus(FundStatus fundstatus)
            {
                _oldfundstatus = fundstatus;
                _newfundstatus = fundstatus;
                InitializeComponent();
            }

            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;
            }

     

        }

    2. 这个自定义控件三个选项值保存在FundStatus类

    public class FundStatus
        {
            ///
            /// 正常
            ///
            private bool _normal = false;
            ///
            /// 注销
            ///
            private bool _cancel = false;
            ///
            /// 冻结
            ///
            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; }
            }

     

        }
    3. 说了这些还没有到说到正题,下面来介绍自定义控件的属性
      自定义控件[ComboFund]属性
       [ Editor(typeof (FundStatusEditor), typeof (UITypeEditor)),    //属性编辑器接口
           TypeConverter(typeof (FundStatusConverter)),              //值转化器
           DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]     //序列化内容保存设置的值
            public FundStatus 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类型。
            ///      
            public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
            {
                if (sourceType == typeof(String)) return true;
                //这里也可以是其它类型的,可以参考后面的链接里面有介绍
                return base.CanConvertFrom(context, sourceType);
            }
            ///
            /// 能否从fundstatus转换到string
            ///   
            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);
            }

            ///
            /// 从string转到 Fundstatus 类型。在Property窗口中显示为string类型。
            ///       
            public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.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);
            }

            ///
            /// 从 fundstatus转换为string
            ///        
            public override 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;
                }
                return base.ConvertFrom(context, culture, value);
            }
    5. 说到这里最重要的东西还没有讲,继承基类UITypeEditor的FundStatusEditor 
      public class FundStatusEditor : UITypeEditor
        {
             [System.Security.Permissions.PermissionSet(System.Security.Permissions.SecurityAction.Demand)] 
            public override System.Drawing.Design.UITypeEditorEditStyle GetEditStyle(System.ComponentModel.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;
            }
        }

    6.这些搞完后如下图,这个就是我们要的属性选择,当然我们还可以做成弹出框的样式还有自己想怎么定义样式就怎么定义,非常方便。
    C#控件开发---控件属性编辑器

    C#控件开发---控件属性编辑器


    参考资料:
    http://msdn.microsoft.com/zh-cn/library/vstudio/system.drawing.design.uitypeeditor.aspx
    http://www.cnblogs.com/mapserver/archive/2006/03/08/345244.html
    http://www.cnblogs.com/guanjinke/archive/2006/12/19/597260.html






你可能感兴趣的:(C#)