您的位置:首页 > 编程语言

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

2013-04-18 17:29 225 查看
http://liang.eu/dotnet-development/programmatically-set-column-width-of-the-propertygrid

http://blog.csdn.net/null1/article/details/2037608

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();

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

base.OnLayout(e);
}
}
}

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

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

using System.Runtime.InteropServices;

public partial class Form1 : Form

class MyClass

希望对你有帮助。

刘婷

在线技术支持工程师

微软全球技术支持中心

我的测试是按照解答二的方法进行的,但是出现了错误,反馈如下:

首先谢谢你的帮助,但是我按照您的说明进行,启动后一旦PropertyGrid获得焦点,就出现错误,信息为:

未处理的“System.NullReferenceException”类型的异常出现在 system.windows.forms.dll 中。

其他信息: Object reference not set to an instance of an object.

请问是什么原因?

代码如下:

using System;

using System.Drawing;

using System.Collections;

using System.ComponentModel;

using System.Windows.Forms;

using System.Data;

using System.Runtime.InteropServices;

using System.Text;

namespace WindowsApplication1

微软工程师的解答:

谢谢你的反馈!

我原先是在VS2005中做了测试。现在在VS.NET2003中测试了一下,确实看到了你说的问题。

这个问题的原因对于从unmanaged code到managed code的回调,在回调方法被调用时,送传递的delegate必须是active的,不能正准备垃圾回收。在我们的程序中有两个回调,一个是EnumChildWindows, 另一个是SetWindowLong。对于前者,找到PropertyGridView子窗口的handle以后就不需要再回调了,因此我们可以将所传递的ChildWindowDelegate声明为局部变量;对于后者,只要你在PropertyGrid中有任何操作,对应的回调方法都将被执行,因此所传递的WindowProcDelegate变量必须是全局的。

因此解决的办法是申明一个全局的WindowProcDelegate变量,然后传递给SetWindowLong函数。

public partial class Form1 : Form

{

     ...

     WindowProcDelegate windowProcDelegate;

     private void Form1_Load(object sender, EventArgs e)

    {

         windowProcDelegate = new WindowProcDelegate(WindowProc);

         bool result = EnumChildWindows(this.propertyGrid1.Handle, new ChildWindowDelegate(EnumChildProc), "PropertyGridView");

            if (result == false)

            {

                defaultProc = GetWindowLong(expectedChild, GWL_WNDPROC);

                SetWindowLong(expectedChild, GWL_WNDPROC, windowProcDelegate);

            }

            MyClass p = new MyClass();

            p.ID = 1;

            p.Name = "aa";

            this.propertyGrid1.SelectedObject = p;

     }        
}

希望对你有帮助。

刘婷

在线技术支持工程师

微软全球技术支持中心

=========================================================

至此问题解决。

未完的路:

如果按照解答一的方法进行,我目前没有测试成功,我的思路是找到PropertyGrid中的System.Windows.Forms.PropertyGridInternal.PropertyGridView子控件,然后将其KeyPress事件绑定到一个指定的处理过程上来实现需要的功能。但是我在VS2003中发现PropertyGridView并不是网上说的Controls[2],而是Controls[1],随后我进行了绑定,然而运行却没有效果,不知道为什么?

此外,我也不知道我的方法是否正确?
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐