既然是一个窗体设计器,那就应该能够设置控件的属性,设置属性最好的当然是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的代码:
- public class TextBoxProperty : PropertyBase
- {
- private TextBox _Control;
- public TextBoxProperty()
- {
- }
- public TextBoxProperty(TextBox control)
- {
- this._Control = control;
- }
- [MyControlAttibute("文本", "获取或者设置控件文本", "")]
- public string Text
- {
- get { return this._Control.Text; }
- set
- {
- this._Control.Text = value;
- }
- }
- [MyControlAttibute("宽度", "获取或者设置控件宽度", "")]
- public int Width
- {
- get { return this._Control.Width; }
- set
- {
- this._Control.Width = (int)value;
- }
- }
- [MyControlAttibute("高度", "获取或者设置控件高度", "")]
- public int Height
- {
- get { return this._Control.Height; }
- set
- {
- this._Control.Height = (int)value;
- }
- }
- [MyControlAttibute("上边距", "获取或者设置控件上边位置", "")]
- public int Top
- {
- get { return this._Control.Top; }
- set
- {
- this._Control.Top = value;
- }
- }
- [MyControlAttibute("左边距", "获取或者设置控件左边位置", "")]
- public int Left
- {
- get { return this._Control.Left; }
- set
- {
- this._Control.Left = value;
- }
- }
- [MyControlAttibute("背景色", "获取或者设置控件背景颜色", "")]
- public Color BackColor
- {
- get { return this._Control.BackColor; }
- set
- {
- this._Control.BackColor = value;
- }
- }
- [MyControlAttibute("前景色", "获取或者设置控件的前景颜色", "")]
- public Color ForeColor
- {
- get { return this._Control.ForeColor; }
- set
- {
- this._Control.ForeColor = value;
- }
- }
- }
你从代码里面已经看出了一些端倪了,在TextBoxProperty中每个要属性都增加了MyControlAttibute,具体Attribute的概念和使用方法您可以参考我的另一篇Blog文《C#基础系列:实现自己的ORM(反射以及Attribute在ORM中的应用)》。这里对Attribute做了详细的介绍(对初学者有效)。所以我就直接贴出MyControlAttibute的代码好了:
- public class MyControlAttibute : Attribute
- {
- private string _PropertyName;
- private string _PropertyDescription;
- private object _DefaultValue;
- public MyControlAttibute(string Name, string Description, object DefalutValue)
- {
- this._PropertyName = Name;
- this._PropertyDescription = Description;
- this._DefaultValue = DefalutValue;
- }
- public MyControlAttibute(string Name, string Description)
- {
- this._PropertyName = Name;
- this._PropertyDescription = Description;
- this._DefaultValue = "";
- }
- public MyControlAttibute(string Name)
- {
- this._PropertyName = Name;
- this._PropertyDescription = "";
- this._DefaultValue = "";
- }
- public string PropertyName
- {
- get { return this._PropertyName; }
- }
- public string PropertyDescription
- {
- get { return this._PropertyDescription; }
- }
- public object DefaultValue
- {
- get { return this._DefaultValue; }
- }
- }
通过上面的两段代码,你已经初步看出了在PropertyGrid中显示中文属性以及仅仅显示我们需要的属性的基本思路。下面就介绍的就是怎么让MyControlAttibute中定义了的中文属性名在PropertyGrid中显示出来。下面这段代码,我仅仅贡献了PropertyStub中这个函数的实现。所以不做过多解释了:
- public override string DisplayName
- {
- get
- {
- if (info != null)
- {
- MyControlAttibute uicontrolattibute = (MyControlAttibute)Attribute.GetCustomAttribute(info, typeof(MyControlAttibute));
- if (uicontrolattibute != null)
- return uicontrolattibute.PropertyName;
- else
- {
- return info.Name;
- }
- }
- else
- return "";
- }
- }
整个代码如下,里面包含两个类,你直接拷贝出来就可以使用了:
- public delegate void PropertyChanged(object Value);
- /// <summary>
- /// 主要是实现中文化属性显示
- /// </summary>
- public class PropertyBase : ICustomTypeDescriptor
- {
- /// <summary>
- /// 下面这段代码来源于:http://www.bluespace.cn/Html/Csdn/2_47/View_4702219.html
- /// </summary>
- /// <returns></returns>
- #region ICustomTypeDescriptor 显式接口定义
- AttributeCollection ICustomTypeDescriptor.GetAttributes()
- {
- return TypeDescriptor.GetAttributes(this, true);
- }
- string ICustomTypeDescriptor.GetClassName()
- {
- return TypeDescriptor.GetClassName(this, true);
- }
- string ICustomTypeDescriptor.GetComponentName()
- {
- return TypeDescriptor.GetComponentName(this, true);
- }
- TypeConverter ICustomTypeDescriptor.GetConverter()
- {
- return TypeDescriptor.GetConverter(this, true);
- }
- EventDescriptor ICustomTypeDescriptor.GetDefaultEvent()
- {
- return TypeDescriptor.GetDefaultEvent(this, true);
- }
- PropertyDescriptor ICustomTypeDescriptor.GetDefaultProperty()
- {
- return null;
- }
- object ICustomTypeDescriptor.GetEditor(Type editorBaseType)
- {
- return TypeDescriptor.GetEditor(this, editorBaseType, true);
- }
- EventDescriptorCollection ICustomTypeDescriptor.GetEvents()
- {
- return TypeDescriptor.GetEvents(this, true);
- }
- EventDescriptorCollection ICustomTypeDescriptor.GetEvents(Attribute[] attributes)
- {
- return TypeDescriptor.GetEvents(this, attributes, true);
- }
- PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties()
- {
- return ((ICustomTypeDescriptor)this).GetProperties(new Attribute[0]);
- }
- PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties(Attribute[] attributes)
- {
- ArrayList props = new ArrayList();
- Type thisType = this.GetType();
- PropertyInfo[] pis = thisType.GetProperties();
- foreach (PropertyInfo p in pis)
- {
- if (p.DeclaringType == thisType || p.PropertyType.ToString() == "System.Drawing.Color")
- {
- //判断属性是否显示
- BrowsableAttribute Browsable = (BrowsableAttribute)Attribute.GetCustomAttribute(p, typeof(BrowsableAttribute));
- if (Browsable != null)
- {
- if (Browsable.Browsable == true || p.PropertyType.ToString() == "System.Drawing.Color")
- {
- PropertyStub psd = new PropertyStub(p, attributes);
- props.Add(psd);
- }
- }
- else
- {
- PropertyStub psd = new PropertyStub(p, attributes);
- props.Add(psd);
- }
- }
- }
- PropertyDescriptor[] propArray = (PropertyDescriptor[])props.ToArray(typeof(PropertyDescriptor));
- return new PropertyDescriptorCollection(propArray);
- }
- object ICustomTypeDescriptor.GetPropertyOwner(PropertyDescriptor pd)
- {
- return this;
- }
- #endregion
- }
- /// <summary>
- /// 下面这段代码来源于:http://www.bluespace.cn/Html/Csdn/2_47/View_4702219.html
- /// </summary>
- #region PropertyStub 定义
- public class PropertyStub : PropertyDescriptor
- {
- PropertyInfo info;
- public PropertyStub(PropertyInfo propertyInfo, Attribute[] attrs)
- : base(propertyInfo.Name, attrs)
- {
- this.info = propertyInfo;
- }
- public override Type ComponentType
- {
- get { return this.info.ReflectedType; }
- }
- public override bool IsReadOnly
- {
- get { return this.info.CanWrite == false; }
- }
- public override Type PropertyType
- {
- get { return this.info.PropertyType; }
- }
- public override bool CanResetValue(object component)
- {
- return false;
- }
- public override object GetValue(object component)
- {
- //Console.WriteLine("GetValue: " + component.GetHashCode());
- try
- {
- return this.info.GetValue(component, null);
- }
- catch
- {
- return null;
- }
- }
- public override void ResetValue(object component)
- {
- }
- public override void SetValue(object component, object value)
- {
- //Console.WriteLine("SetValue: " + component.GetHashCode());
- this.info.SetValue(component, value, null);
- }
- public override bool ShouldSerializeValue(object component)
- {
- return false;
- }
- //通过重载下面这个属性,可以将属性在PropertyGrid中的显示设置成中文
- public override string DisplayName
- {
- get
- {
- if (info != null)
- {
- MyControlAttibute uicontrolattibute = (MyControlAttibute)Attribute.GetCustomAttribute(info, typeof(MyControlAttibute));
- if (uicontrolattibute != null)
- return uicontrolattibute.PropertyName;
- else
- {
- return info.Name;
- }
- }
- else
- return "";
- }
- }
- }
- #endregion
修改后的Form界面如下:
Form中由于我仅仅是演示了TextBox所以我就是直接将创建TextBoxProperty对象的代码放在了Control_Click中:
//我这里仅仅做TextBox的属性演示,如果是其它的控件的话,那么你需要设计不同的ControlProperty(比如TextBoxProperty,ComboBoxProperty)
if (sender is TextBox)
{
this.propertyGrid1.SelectedObject = new TextBoxProperty((TextBox)sender);
}
else
{
this.propertyGrid1.SelectedObject = null;
}
对于实际的需要来说应该是根据Control的类型,通过工厂模式来创建ControlProperty。
Form的整个代码如下,窗体如上图所示:
- //在Form中增加几个Button,分别命名为cmdArrow,cmdLabel,cmdTextBox,cmdComboBox,cmdGroupBox
- public partial class Form1 : Form
- {
- private MouseHook _MouseHook;
- //我们将所有的已经与具体控件关联了的UISizeKnob缓存在这个HashTable中
- private Hashtable _HashUISizeKnob;
- //负责控件移动的类
- private Hashtable _HashUIMoveKnob;
- public Form1()
- {
- InitializeComponent();
- this._MouseHook = new MouseHook(this);
- this._HashUISizeKnob = new Hashtable();
- this._HashUIMoveKnob = new Hashtable();
- //为了简洁明了,我们在ControlAdded中来设置具体控件和UISizeKnob的关联
- this.ControlAdded += new ControlEventHandler(Form1_ControlAdded);
- }
- void Form1_ControlAdded(object sender, ControlEventArgs e)
- {
- if (!(e.Control is UISizeDot))
- {
- this._HashUISizeKnob.Add(e.Control, new UISizeKnob(e.Control));
- this._HashUIMoveKnob.Add(e.Control, new UIMoveKnob(e.Control));
- //点击控件的时候,显示控件的选择
- e.Control.Click += new EventHandler(Control_Click);
- }
- }
- void Control_Click(object sender, EventArgs e)
- {
- //寿险清除已经选择的控件
- foreach (UISizeKnob knob in this._HashUISizeKnob.Values)
- {
- knob.ShowUISizeDots(false);
- }
- //System.ComponentModel.Design.ISelectionService
- //System.Drawing.Design.IToolboxService
- try
- {
- ((UISizeKnob)this._HashUISizeKnob[sender]).ShowUISizeDots(true);
- //我这里仅仅做TextBox的属性演示,如果是其它的控件的话,那么你需要设计不同的ControlProperty(比如TextBoxProperty,ComboBoxProperty)
- if (sender is TextBox)
- {
- this.propertyGrid1.SelectedObject = new TextBoxProperty((TextBox)sender);
- }
- else
- {
- this.propertyGrid1.SelectedObject = null;
- }
- }
- catch { }
- }
- private void cmdArrow_Click(object sender, EventArgs e)
- {
- SettingService.Instance.SelectedToolBoxControl = null;
- }
- private void cmdLabel_Click(object sender, EventArgs e)
- {
- SettingService.Instance.SelectedToolBoxControl = new Label();
- }
- private void cmdTextBox_Click(object sender, EventArgs e)
- {
- SettingService.Instance.SelectedToolBoxControl = new TextBox();
- }
- private void cmdComboBox_Click(object sender, EventArgs e)
- {
- SettingService.Instance.SelectedToolBoxControl = new ComboBox();
- }
- private void cmdGroupBox_Click(object sender, EventArgs e)
- {
- SettingService.Instance.SelectedToolBoxControl = new GroupBox();
- }
- }
好了,让PropertyGrid显示中文属性的思路和代码都给了,希望能够给你点启发和帮助。
相关文章: