C#基础系列:开发自己的窗体设计器(PropertyGrid显示中文属性名)

 

既然是一个窗体设计器,那就应该能够设置控件的属性,设置属性最好的当然是PropertyGrid了,我们仅仅需要使用一个PropertyGrid.SelectedObject = Control就可以搞定,让PropertyGrid显示Control的所有属性。可是这里显示的属性名是英文的。对于我们开发人员来说这无可厚非,我们也乐于接受。并且让PropertyGrid显示中文属性名,这对于我们开发人员的使用来说显得多此一举。可是,对于我这种类型的一个应用工具,英文属性名对于很多客户来说可能就很难懂了。所以应该让PrpertyGrid能够显示中文属性名。

如图:

 

另外,对于这样的一个系统。并不是控件的所有属性都是用户希望的,可能用户希望看到的仅仅是控件高度、控件宽度、控件文本。。等等的属性,但是如果直接将一个控件属性全部显示给用户的话,估计对用户造成的干扰和困惑是很大的。如何解决这个问题呢?其实用户控件开发的时候,如果我们不希望此属性在PropertyGrid中显示,我们可以设置这个控件的Attribute,如:

[Browsable(false)]

public int Width

{

    get { }

    set { }

}

通过使用BrowsableAttribute就可以设置将此属性对PropertyGrid隐藏。

 

你可能要问到了,对于控件来说,其中的很多属性都是直接继承来的,我们并没有办法控制是否对PropertyGrid隐藏啊?呵呵,对啊,这就是我下面要说的解决方法(当然此方法显得不是很灵活,但是对于这种类型的系统的确相当有用)。

在我的解决方式中,我不直接这样PropertyGrid.SelectedObject = Control,而是把这个Control替换成一个专门为此类型的Control设计的类对象上。比如我对TextBox设计了一个TextBoxProperty,这样我们使用的是PropertyGrid.SelectedObject = TextBoxProperty的一个对象。

下面就是TextBoxProperty的代码:

  1. public class TextBoxProperty : PropertyBase
  2. {
  3.     private TextBox _Control;
  4.     public TextBoxProperty()
  5.     {
  6.     }
  7.     public TextBoxProperty(TextBox control)
  8.     {
  9.         this._Control = control;
  10.     }
  11.     [MyControlAttibute("文本""获取或者设置控件文本""")]
  12.     public string Text
  13.     {
  14.         get { return this._Control.Text; }
  15.         set
  16.         {
  17.             this._Control.Text = value;
  18.         }
  19.     }
  20.     [MyControlAttibute("宽度""获取或者设置控件宽度""")]
  21.     public int Width
  22.     {
  23.         get { return this._Control.Width; }
  24.         set
  25.         {
  26.             this._Control.Width = (int)value;
  27.         }
  28.     }
  29.     [MyControlAttibute("高度""获取或者设置控件高度""")]
  30.     public int Height
  31.     {
  32.         get { return this._Control.Height; }
  33.         set
  34.         {
  35.             this._Control.Height = (int)value;
  36.         }
  37.     }
  38.     [MyControlAttibute("上边距""获取或者设置控件上边位置""")]
  39.     public int Top
  40.     {
  41.         get { return this._Control.Top; }
  42.         set
  43.         {
  44.             this._Control.Top = value;
  45.         }
  46.     }
  47.     [MyControlAttibute("左边距""获取或者设置控件左边位置""")]
  48.     public int Left
  49.     {
  50.         get { return this._Control.Left; }
  51.         set
  52.         {
  53.             this._Control.Left = value;
  54.         }
  55.     }
  56.     [MyControlAttibute("背景色""获取或者设置控件背景颜色""")]
  57.     public Color BackColor
  58.     {
  59.         get { return this._Control.BackColor; }
  60.         set
  61.         {
  62.             this._Control.BackColor = value;
  63.         }
  64.     }
  65.     [MyControlAttibute("前景色""获取或者设置控件的前景颜色""")]
  66.     public Color ForeColor
  67.     {
  68.         get { return this._Control.ForeColor; }
  69.         set
  70.         {
  71.             this._Control.ForeColor = value;
  72.         }
  73.     }
  74. }

你从代码里面已经看出了一些端倪了,在TextBoxProperty中每个要属性都增加了MyControlAttibute,具体Attribute的概念和使用方法您可以参考我的另一篇Blog文《C#基础系列:实现自己的ORM(反射以及AttributeORM中的应用)》。这里对Attribute做了详细的介绍(对初学者有效)。所以我就直接贴出MyControlAttibute的代码好了:

  1. public class MyControlAttibute : Attribute
  2. {
  3.     private string _PropertyName;
  4.     private string _PropertyDescription;
  5.     private object _DefaultValue;
  6.     public MyControlAttibute(string Name, string Description, object DefalutValue)
  7.     {
  8.         this._PropertyName = Name;
  9.         this._PropertyDescription = Description;
  10.         this._DefaultValue = DefalutValue;
  11.     }
  12.     public MyControlAttibute(string Name, string Description)
  13.     {
  14.         this._PropertyName = Name;
  15.         this._PropertyDescription = Description;
  16.         this._DefaultValue = "";
  17.     }
  18.     public MyControlAttibute(string Name)
  19.     {
  20.         this._PropertyName = Name;
  21.         this._PropertyDescription = "";
  22.         this._DefaultValue = "";
  23.     }
  24.     public string PropertyName
  25.     {
  26.         get { return this._PropertyName; }
  27.     }
  28.     public string PropertyDescription
  29.     {
  30.         get { return this._PropertyDescription; }
  31.     }
  32.     public object DefaultValue
  33.     {
  34.         get { return this._DefaultValue; }
  35.     }
  36. }

通过上面的两段代码,你已经初步看出了在PropertyGrid中显示中文属性以及仅仅显示我们需要的属性的基本思路。下面就介绍的就是怎么让MyControlAttibute中定义了的中文属性名在PropertyGrid中显示出来。下面这段代码,我仅仅贡献了PropertyStub中这个函数的实现。所以不做过多解释了:

  1. public override string DisplayName
  2. {
  3.     get
  4.     {
  5.         if (info != null)
  6.         {
  7.             MyControlAttibute uicontrolattibute = (MyControlAttibute)Attribute.GetCustomAttribute(info, typeof(MyControlAttibute));
  8.             if (uicontrolattibute != null)
  9.                 return uicontrolattibute.PropertyName;
  10.             else
  11.             {
  12.                 return info.Name;
  13.             }
  14.         }
  15.         else
  16.             return "";
  17.     }
  18. }

整个代码如下,里面包含两个类,你直接拷贝出来就可以使用了:

  1. public delegate void PropertyChanged(object Value);
  2. /// <summary>
  3. /// 主要是实现中文化属性显示
  4. /// </summary>
  5. public class PropertyBase : ICustomTypeDescriptor
  6. {
  7.     /// <summary>
  8.     /// 下面这段代码来源于:http://www.bluespace.cn/Html/Csdn/2_47/View_4702219.html
  9.     /// </summary>
  10.     /// <returns></returns>
  11.     #region ICustomTypeDescriptor 显式接口定义
  12.     AttributeCollection ICustomTypeDescriptor.GetAttributes()
  13.     {
  14.         return TypeDescriptor.GetAttributes(thistrue);
  15.     }
  16.     string ICustomTypeDescriptor.GetClassName()
  17.     {
  18.         return TypeDescriptor.GetClassName(thistrue);
  19.     }
  20.     string ICustomTypeDescriptor.GetComponentName()
  21.     {
  22.         return TypeDescriptor.GetComponentName(thistrue);
  23.     }
  24.     TypeConverter ICustomTypeDescriptor.GetConverter()
  25.     {
  26.         return TypeDescriptor.GetConverter(thistrue);
  27.     }
  28.     EventDescriptor ICustomTypeDescriptor.GetDefaultEvent()
  29.     {
  30.         return TypeDescriptor.GetDefaultEvent(thistrue);
  31.     }
  32.     PropertyDescriptor ICustomTypeDescriptor.GetDefaultProperty()
  33.     {
  34.         return null;
  35.     }
  36.     object ICustomTypeDescriptor.GetEditor(Type editorBaseType)
  37.     {
  38.         return TypeDescriptor.GetEditor(this, editorBaseType, true);
  39.     }
  40.     EventDescriptorCollection ICustomTypeDescriptor.GetEvents()
  41.     {
  42.         return TypeDescriptor.GetEvents(thistrue);
  43.     }
  44.     EventDescriptorCollection ICustomTypeDescriptor.GetEvents(Attribute[] attributes)
  45.     {
  46.         return TypeDescriptor.GetEvents(this, attributes, true);
  47.     }
  48.     PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties()
  49.     {
  50.         return ((ICustomTypeDescriptor)this).GetProperties(new Attribute[0]);
  51.     }
  52.     PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties(Attribute[] attributes)
  53.     {
  54.         ArrayList props = new ArrayList();
  55.         Type thisType = this.GetType();
  56.         PropertyInfo[] pis = thisType.GetProperties();
  57.         foreach (PropertyInfo p in pis)
  58.         {
  59.             if (p.DeclaringType == thisType || p.PropertyType.ToString() == "System.Drawing.Color")
  60.             {
  61.                 //判断属性是否显示
  62.                 BrowsableAttribute Browsable = (BrowsableAttribute)Attribute.GetCustomAttribute(p, typeof(BrowsableAttribute));
  63.                 if (Browsable != null)
  64.                 {
  65.                     if (Browsable.Browsable == true || p.PropertyType.ToString() == "System.Drawing.Color")
  66.                     {
  67.                         PropertyStub psd = new PropertyStub(p, attributes);
  68.                         props.Add(psd);
  69.                     }
  70.                 }
  71.                 else
  72.                 {
  73.                     PropertyStub psd = new PropertyStub(p, attributes);
  74.                     props.Add(psd);
  75.                 }
  76.             }
  77.         }
  78.         PropertyDescriptor[] propArray = (PropertyDescriptor[])props.ToArray(typeof(PropertyDescriptor));
  79.         return new PropertyDescriptorCollection(propArray);
  80.     }
  81.     object ICustomTypeDescriptor.GetPropertyOwner(PropertyDescriptor pd)
  82.     {
  83.         return this;
  84.     }
  85.     #endregion
  86. }
  87. /// <summary>
  88. /// 下面这段代码来源于:http://www.bluespace.cn/Html/Csdn/2_47/View_4702219.html
  89. /// </summary>
  90. #region PropertyStub 定义
  91. public class PropertyStub : PropertyDescriptor
  92. {
  93.     PropertyInfo info;
  94.     public PropertyStub(PropertyInfo propertyInfo, Attribute[] attrs)
  95.         : base(propertyInfo.Name, attrs)
  96.     {
  97.         this.info = propertyInfo;
  98.     }
  99.     public override Type ComponentType
  100.     {
  101.         get { return this.info.ReflectedType; }
  102.     }
  103.     public override bool IsReadOnly
  104.     {
  105.         get { return this.info.CanWrite == false; }
  106.     }
  107.     public override Type PropertyType
  108.     {
  109.         get { return this.info.PropertyType; }
  110.     }
  111.     public override bool CanResetValue(object component)
  112.     {
  113.         return false;
  114.     }
  115.     public override object GetValue(object component)
  116.     {
  117.         //Console.WriteLine("GetValue: " + component.GetHashCode());
  118.         try
  119.         {
  120.             return this.info.GetValue(component, null);
  121.         }
  122.         catch
  123.         {
  124.             return null;
  125.         }
  126.     }
  127.     public override void ResetValue(object component)
  128.     {
  129.     }
  130.     public override void SetValue(object component, object value)
  131.     {
  132.         //Console.WriteLine("SetValue: " + component.GetHashCode());
  133.         this.info.SetValue(component, value, null);
  134.     }
  135.     public override bool ShouldSerializeValue(object component)
  136.     {
  137.         return false;
  138.     }
  139.     //通过重载下面这个属性,可以将属性在PropertyGrid中的显示设置成中文
  140.     public override string DisplayName
  141.     {
  142.         get
  143.         {
  144.             if (info != null)
  145.             {
  146.                 MyControlAttibute uicontrolattibute = (MyControlAttibute)Attribute.GetCustomAttribute(info, typeof(MyControlAttibute));
  147.                 if (uicontrolattibute != null)
  148.                     return uicontrolattibute.PropertyName;
  149.                 else
  150.                 {
  151.                     return info.Name;
  152.                 }
  153.             }
  154.             else
  155.                 return "";
  156.         }
  157.     }
  158. }
  159. #endregion

修改后的Form界面如下:

 

Form中由于我仅仅是演示了TextBox所以我就是直接将创建TextBoxProperty对象的代码放在了Control_Click中:

//我这里仅仅做TextBox的属性演示,如果是其它的控件的话,那么你需要设计不同的ControlProperty(比如TextBoxPropertyComboBoxProperty

if (sender is TextBox)

{

    this.propertyGrid1.SelectedObject = new TextBoxProperty((TextBox)sender);

}

else

{

    this.propertyGrid1.SelectedObject = null;

}

对于实际的需要来说应该是根据Control的类型,通过工厂模式来创建ControlProperty

Form的整个代码如下,窗体如上图所示:

 

  1. //在Form中增加几个Button,分别命名为cmdArrow,cmdLabel,cmdTextBox,cmdComboBox,cmdGroupBox
  2. public partial class Form1 : Form
  3. {
  4.     private MouseHook _MouseHook;
  5.     //我们将所有的已经与具体控件关联了的UISizeKnob缓存在这个HashTable中
  6.     private Hashtable _HashUISizeKnob;
  7.     //负责控件移动的类
  8.     private Hashtable _HashUIMoveKnob;
  9.     public Form1()
  10.     {
  11.         InitializeComponent();
  12.         this._MouseHook = new MouseHook(this);
  13.         this._HashUISizeKnob = new Hashtable();
  14.         this._HashUIMoveKnob = new Hashtable();
  15.         //为了简洁明了,我们在ControlAdded中来设置具体控件和UISizeKnob的关联
  16.         this.ControlAdded += new ControlEventHandler(Form1_ControlAdded);
  17.     }
  18.     void Form1_ControlAdded(object sender, ControlEventArgs e)
  19.     {
  20.         if (!(e.Control is UISizeDot))
  21.         {
  22.             this._HashUISizeKnob.Add(e.Control, new UISizeKnob(e.Control));
  23.             this._HashUIMoveKnob.Add(e.Control, new UIMoveKnob(e.Control));
  24.             
  25.             //点击控件的时候,显示控件的选择
  26.             e.Control.Click += new EventHandler(Control_Click);
  27.         }
  28.     }
  29.     void Control_Click(object sender, EventArgs e)
  30.     {
  31.         //寿险清除已经选择的控件
  32.         foreach (UISizeKnob knob in this._HashUISizeKnob.Values)
  33.         {
  34.             knob.ShowUISizeDots(false);
  35.         }
  36.         //System.ComponentModel.Design.ISelectionService
  37.         //System.Drawing.Design.IToolboxService
  38.         try 
  39.         {
  40.             ((UISizeKnob)this._HashUISizeKnob[sender]).ShowUISizeDots(true);
  41.         //我这里仅仅做TextBox的属性演示,如果是其它的控件的话,那么你需要设计不同的ControlProperty(比如TextBoxProperty,ComboBoxProperty)
  42.         if (sender is TextBox)
  43.         {
  44.             this.propertyGrid1.SelectedObject = new TextBoxProperty((TextBox)sender);
  45.         }
  46.         else
  47.         {
  48.             this.propertyGrid1.SelectedObject = null;
  49.         }
  50.         }
  51.         catch { }
  52.     }
  53.     
  54.     private void cmdArrow_Click(object sender, EventArgs e)
  55.     {
  56.         SettingService.Instance.SelectedToolBoxControl = null;
  57.     }
  58.     private void cmdLabel_Click(object sender, EventArgs e)
  59.     {
  60.         SettingService.Instance.SelectedToolBoxControl = new Label();
  61.     }
  62.     private void cmdTextBox_Click(object sender, EventArgs e)
  63.     {
  64.         SettingService.Instance.SelectedToolBoxControl = new TextBox();
  65.     }
  66.     private void cmdComboBox_Click(object sender, EventArgs e)
  67.     {
  68.         SettingService.Instance.SelectedToolBoxControl = new ComboBox();
  69.     }
  70.     private void cmdGroupBox_Click(object sender, EventArgs e)
  71.     {
  72.         SettingService.Instance.SelectedToolBoxControl = new GroupBox();
  73.     }
  74. }

好了,让PropertyGrid显示中文属性的思路和代码都给了,希望能够给你点启发和帮助。

 

相关文章:

 

C#基础系列:开发自己的窗体设计器(总纲)

C#基础系列:开发自己的窗体设计器(在容器上拖动鼠标增加控件)

C#基础系列:开发自己的窗体设计器(实现控件的选择)

C#基础系列:开发自己的窗体设计器(实现控件的拖动)

 

  • 6
    点赞
  • 34
    收藏
    觉得还不错? 一键收藏
  • 15
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 15
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值