您的位置:首页 > 编程语言 > C#

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

2014-03-14 21:40 363 查看
最近项目需要用到自定义控件的属性需要多选,我们知道默认的属性一般都是下拉输入之类的,也有多选,但是我需要的是checkbox,没有现成的,百度发现微软有提供接口UITypeEditor ,继承这个基类就可以搞定了。废话不多说
了,下面来具体代码说明。


首先来一段官方资料:

UITypeEditor 类 提供可用于设计值编辑器的基类,这些编辑器可提供用户界面
(UI),用来表示和编辑所支持的数据类型的对象值。 
UITypeEditor
类提供了一个基类,您可以从其派生或将其扩展,来为设计时环境实现一个自定义类型编辑器。通常,您的自定义类型编辑器与 PropertyGrid 控件进行交互。 

在文本框值编辑器不足以有效地选择某些类型的值的情况下,自定义类型编辑器非常有用。

若要实现自定义设计时 UI 类型编辑器,必须执行下列步骤:

定义一个从 UITypeEditor 派生的类。

重写 EditValue 方法以处理用户界面、用户输入操作以及值的分配。

重写 GetEditStyle 方法,以便将编辑器将使用的编辑器样式的类型通知给“属性”窗口。
 

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

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

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

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

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

1.
 首先建立一个usercontrol






以下是源码 :

 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 自定义控件[/b]
 
     
     
     ComboFund control = (ComboFund)context.Instance;
 
     
     
     
PropertyFundStatus pfs = new
PropertyFundStatus(control.FundStatus);

 
     
     
     
editorService.DropDownControl(pfs);

 
     
     
      value =
pfs.FundStatus;

 
     
     
      return
value;
 
     
     
  }
 
     
    }
 
     
    return value;
 
      }
 
  }

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








参考资料:
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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐