既然是一个窗体设计器,那就应该能够设置控件的属性,设置属性最好的当然是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[]);
}
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>
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 "";
}
}
}

修改后的Form界面如下:

所以我就是直接将创建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显示中文属性的思路和代码都给了,希望能够给你点启发和帮助。

相关文章:

原文链接:

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

其他参考文献:

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

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

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

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

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

  1. Windows 窗体设计器(Windows Forms Designer)入门

      Visual Studio 2010 更新:2010 年 9 月 Windows 窗体设计器提供多个用于生成 Windows 窗体应用程序的工具. 本演练阐释如何使用设计器提供的各种工具生成应用程 ...

  2. 解析大型.NET ERP系统核心组件 查询设计器 报表设计器 窗体设计器 工作流设计器 任务计划设计器

    企业管理软件包含一些公共的组件,这些基础的组件在每个新项目立项阶段就必须考虑.核心的稳定不变功能,方便系统开发与维护,也为系统二次开发提供了诸多便利.比如通用权限管理系统,通用附件管理,通用查询等组件 ...

  3. 通过用 .NET 生成自定义窗体设计器来定制应用程序

    通过用 .NET 生成自定义窗体设计器来定制应用程序 https://www.microsoft.com/china/MSDN/library/netFramework/netframework/Cu ...

  4. [翻译]用于.NET Core的Windows窗体设计器发布

    本文由微信公众号<开发者精选资讯>翻译首发,转载请注明来源 今天我们很高兴地宣布,.NET Core项目的Windows窗体设计器现在可以在 Visual Studio 2019 16.6 ...

  5. 在.NET Core 3.0 Preview上使用Windows窗体设计器

    支持使用基于Windows窗体应用程序的.NET Core 3.0(预览)的Windows窗体设计器 介绍 截至撰写本文时,Microsoft和社区目前正在测试.NET Core 3.0.如果您在.N ...

  6. WinForm编程时窗体设计器中ComboBox控件大小的设置

    问题描述: 在VS中的窗体设计器中拖放一个ComboBox控件后想调整控件的大小.发现在控件上用鼠标只能拖动宽度(Width)无法拖动(Height). 解决过程: 1.控件无法拖动,就在属性窗口中设 ...

  7. C#用DesignSurface实现一个简单的窗体设计器

    System.ComponentModel.Design.DesignSurface是为设计组件提供一个用户界面,通过它可以实现一个简单的窗体设计器. 在构建之前,我们需要引入System.Desig ...

  8. C#自定义运行时窗体设计器Runtime FormDesigner

    写在前面:因为业务的需要,有时会使用到自定义运行时窗体设计器Runtime FormDesigner,实现的功能,就是IDE设计器的简化.设想一下,如果可以在程序运行时,再设计一个Form,然后编译代 ...

  9. C# winFrom窗体设计问题-部分文件打不开窗体设计器 变成类.cs

    https://zhidao.baidu.com/question/1513483178103163220.html C# winform程序设计的时候,出现了问题.默认主窗体form1(改名form ...

随机推荐

  1. hadoop实战–搭建eclipse开发环境及编写Hello World

    原创文章,转载请注明: 转载自工学1号馆 欢迎关注我的个人博客:www.wuyudong.com, 更多云计算与大数据的精彩文章 1.在eclise中安装hadoop的插件并配置 在上篇文章<编 ...

  2. 数位类统计问题--数位DP

    有一类与数位有关的区间统计问题.这类问题往往具有比较浓厚的数学味道,无法暴力求解,需要在数位上进行递推等操作.这类问题往往需要一些预处理,这就用到了数位DP. 本文地址:http://www.cnbl ...

  3. 利用eclipse抽取 代码片段为方法

    选取要被抽取成方法的代码片段,右键->Refactor--->Extract Method 填写方法名称     抽取后成了这个样子:

  4. Effective Java 18 Prefer interfaces to abstract classes

    Feature Interface Abstract class Defining a type that permits multiple implementations Y Y Permitted ...

  5. 【mysql】关于innodb中MVCC的一些理解

    一.MVCC简介 MVCC (Multiversion Concurrency Control),即多版本并发控制技术,它使得大部分支持行锁的事务引擎,不再单纯的使用行锁来进行数据库的并发控制,取而代 ...

  6. Apache CXF自定义拦截器

    为什么设计拦截器?1.为了在webservice请求过程中,能动态操作请求和响应数据,CXF设计了拦截器 拦截器分类: 1.按所处的位置分:服务器端拦截器,客户端拦截器. 2.按消息的方向分:入拦截器 ...

  7. centOS 6.5下升级mysql,从5.1升级到5.7

    1.备份数据库,升级MySQL通常不会丢失数据,但保险起见,我们需要做这一步.输入命令: mysqldump -u xxx -h xxx -P 3306 -p --all-databases > ...

  8. 设计模式C#实现(四)——迭代器模式

    迭代器模式:提供一种方法顺序访问一个聚合对象中的各个元素,而又不暴露其内部的表示. UML类图: 煎饼屋和餐厅合并了!但是有个小问题,虽然两家都同意实现相同的菜单项MenuItem,但是煎饼屋想使用A ...

  9. 提高IT团队工作效率的建议

    过分强调个人主义,不科学分工,内部成员的冲突等,都将导致IT团队没有凝聚力,直接影响团队合作项目的完成.如何提高团队工作效率,相信很多IT经理人都想过这类问题.日前,国外科技网站CIO撰文就如何提高I ...

  10. 记一次查内存异常问题(续《记一次Web应用CPU偏高》)

    继上一次查应用的CPU飙高问题(http://www.cnblogs.com/hzmark/p/JVM_CPU.html)过去10天了.上次只是定位到了是一个第三方包占用了大量的CPU使用,但没有细致 ...