Spiga

如何使用代码设置PropertyGrid的标签栏宽度

2008-09-11 00:32 by 挨踢人, 2130 visits, 收藏, 编辑

Visual Studio里自带的PropertyGrid功能强大,用好了可以省去不少工作。前几天使用到了这个控件,使用过程中发现无法控制控件里标签栏和属性值栏的宽度,Google了一番,发现网上介绍使用这个控件的文章不少,但却没有介绍如何在代码里调整PropertyGrid的标签栏和代码栏的宽度的文章。后来到CodeProject搜索了一下,发现了不少关于PropertyGrid的文章。偶e文不是很好,硬着头皮一篇一篇看了过去,最后功夫不负有心人,总算找到了几篇介绍如何调整标签栏宽度的文章:

Add Custom Properties to a PropertyGrid

.NET PropertyGrid -> How to set column width and description window height(托伟大的GFW的福,这篇文章我是通过TOR才能浏览到)

虽然是不同作者写的,但异曲同工,原理都是通过反射来调用PropertyGrid里自带的的私有成员来实现的。

那么,该如何实现这个功能呢?方法有两种,一种是设置PropertyGrid的labelWidth私有变量;另一种方法是调用PropertyGrid的MoveSplitterTo私有函数。下面详细介绍这两种方法:

 

第一种:直接设置 labelWidth 私有变量

 

labelWidth这个私有变量的用途是见名知意,我就不多说了,下面是如何使用反射来设置它的值的方法:

先新建一个类,继承于PropertyGrid,然后重写它的OnLayout方法,代码如下:

 

using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.Reflection;

namespace TestProject
{
    class PropertyGridEx:PropertyGrid
    {
        protected override void OnLayout(LayoutEventArgs e)
        {
            int width = 200;
            Control propertyGridView = this.Controls[2];
            Type propertyGridViewType = propertyGridView.GetType();

            FieldInfo fldLabelWidth = propertyGridViewType.GetField("labelWidth", BindingFlags.Instance | BindingFlags.NonPublic);
            fldLabelWidth.SetValue(propertyGridView, width);

            base.OnLayout(e);
        }
    }
}
 

为什么要有Control propertyGridView = this.Controls[2];这一行代码呢?原来,PropertyGrid控件本身是一个复合控件,它其实是有三个子窗口组成的:PropertyGridToolBar, PropertyGridView和Description Pane。其中子窗口PropertyGridView,也就是this.Controls[2](在VS的代码提示里PropertyGrid控件没有Controls这个属性,说明微软不提倡直接使用此方法,但可以手工直接输入并能正常工作),才是我们平时进行属性设置操作的地方。这里就是先获得PropertyGridView对象的引用,然后再通过反射直接设置它的labelWidth私有变量来实现设置标签栏宽度的。

这个方法有一个小bug:当设置的labelWidth比默认值小的话,鼠标点击PropertyGrid的属性值栏的右边不能选中该属性。如下图的AutoSizeMode属性:

image

正常情况下,点击图中蓝色区域内均可选中激活该属性的下拉框编辑界面,但通过上面说的方法重写OnLayout方法后,点击红色方框区域内均无法选中该属性,这是个bug的原因有空再研究研究。下面介绍另一种方法。

 

第二种:调用 MoveSplitterTo 私有函数

这个方法也是重写PropertyGrid的OnLayout方法,在里面通过反射调用PropertyGridView对象的MoveSplitterTo函数,这个函数是PropertyGridView对象自带的一个私有方法。我有点想不明白微软既然已经想到并实现了调整标签栏宽度这个功能,但为什么不把这个函数公开或者直接提供一个设置PropertyGrid的标签栏宽度的方法呢?

代码如下:

using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.Reflection;

namespace TestProject
{
    class PropertyGridEx:PropertyGrid
    {
        protected override void OnLayout(LayoutEventArgs e)
        {
            int width = 200;
            Control propertyGridView = this.Controls[2];
            Type propertyGridViewType = propertyGridView.GetType();

            propertyGridViewType.InvokeMember("MoveSplitterTo",
                    BindingFlags.InvokeMethod | BindingFlags.NonPublic | BindingFlags.Instance,
                    null, propertyGridView, new object[] { width });

            base.OnLayout(e);
        }
    }
}

 

这种方法没有第一种方法所说的那个bug,在我的项目里它运行的很好。运行结果截图如下:

image

 

演示程序:这么简单的东西,不需要演示了吧?

 

原创文章,欢迎转载。转载请务必标明来源和原文链接,否则谢绝转载,谢谢合作。