当前位置: 首页 > news >正文

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的代码:

 

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(反射以及AttributeORM中的应用)》。这里对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>
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#基础系列:开发自己的窗体设计器(实现控件的拖动)

 

转载于:https://www.cnblogs.com/rainbow70626/p/6002188.html

相关文章:

  • CSS3盒模型-display:box
  • 2016 10 28考试 dp 乱搞 树状数组
  • Mac 下安装运行Rocket.chat
  • 阶段2-新手上路\项目-移动物体监控系统\Sprint1-声音报警子系统开发\第3节-嵌入式播放器移植...
  • 如何一步一步用DDD设计一个电商网站(二)—— 项目架构
  • Java各种排序算法详解
  • php底层运行原理
  • python之map、filter、reduce、lambda函数 转
  • Linux 命令行总结
  • jquery.spinner数字智能加减插件源代码效果
  • 关键字提取算法TF-IDF
  • 微软Madoko常见问题总结
  • 【Python基础学习二】定义变量、判断、循环、函数基本语法
  • HTML5 Canvas 练习及知识点分享之绘制圆及曲线(一)
  • redis安装出错
  • @angular/forms 源码解析之双向绑定
  • bearychat的java client
  • canvas 高仿 Apple Watch 表盘
  • Computed property XXX was assigned to but it has no setter
  • Fabric架构演变之路
  • niucms就是以城市为分割单位,在上面 小区/乡村/同城论坛+58+团购
  • Redis的resp协议
  • SQLServer之索引简介
  • 表单中readonly的input等标签,禁止光标进入(focus)的几种方式
  • 大整数乘法-表格法
  • 第三十一到第三十三天:我是精明的小卖家(一)
  • 数据结构java版之冒泡排序及优化
  • 听说你叫Java(二)–Servlet请求
  • 问:在指定的JSON数据中(最外层是数组)根据指定条件拿到匹配到的结果
  • 学习笔记:对象,原型和继承(1)
  • 怎么将电脑中的声音录制成WAV格式
  • 自制字幕遮挡器
  • Redis4.x新特性 -- 萌萌的MEMORY DOCTOR
  • ​​​​​​​​​​​​​​汽车网络信息安全分析方法论
  • # 再次尝试 连接失败_无线WiFi无法连接到网络怎么办【解决方法】
  • (Forward) Music Player: From UI Proposal to Code
  • (webRTC、RecordRTC):navigator.mediaDevices undefined
  • (阿里云万网)-域名注册购买实名流程
  • (附源码)计算机毕业设计ssm-Java网名推荐系统
  • (十)c52学习之旅-定时器实验
  • (四)Controller接口控制器详解(三)
  • (算法)求1到1亿间的质数或素数
  • (转)eclipse内存溢出设置 -Xms212m -Xmx804m -XX:PermSize=250M -XX:MaxPermSize=356m
  • .mysql secret在哪_MySQL如何使用索引
  • .NET平台开源项目速览(15)文档数据库RavenDB-介绍与初体验
  • .Net转Java自学之路—SpringMVC框架篇六(异常处理)
  • //解决validator验证插件多个name相同只验证第一的问题
  • /deep/和 >>>以及 ::v-deep 三者的区别
  • [Android Pro] android 混淆文件project.properties和proguard-project.txt
  • [Android]Android开发入门之HelloWorld
  • [Angularjs]asp.net mvc+angularjs+web api单页应用
  • [APIO2015]巴厘岛的雕塑
  • [BJDCTF2020]The mystery of ip
  • [BROADCASTING]tensor的扩散机制
  • [C#]winform部署PaddleOCRV3推理模型