How can I set the column width of a Property Grid?
Asked Answered
M

8

15

I am using property grid in my application to display the name and value of the properties of an object.

By default the width of the columns (name and property) are at a ratio of 50:50. and we have an option of sliding the splitter to change this width. I would like to know how this width can be adjusted programmatically so that it can be set at say 25:75.

Medlock answered 16/9, 2012 at 13:14 Comment(0)
Q
4

As in this answer is mentioned :

There is no property to do that and you have to hack the control. first add this code :

    public static void SetLabelColumnWidth(PropertyGrid grid, int width)
{
    if (grid == null)
        throw new ArgumentNullException("grid");

    // get the grid view
    Control view = (Control)grid.GetType().GetField("gridView", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(grid);

    // set label width
    FieldInfo fi = view.GetType().GetField("labelWidth", BindingFlags.Instance | BindingFlags.NonPublic);
    fi.SetValue(view, width);

    // refresh
    view.Invalidate();
}

and call it with the size what you want . like this:

SetLabelColumnWidth(propertyGrid1, 100);
Quartering answered 16/9, 2012 at 14:3 Comment(6)
Field name "labelWidth" not exist! Still, size is 50:50!Medlock
I use .Net 4.5 in my project and there is no problem with code.Quartering
How can I change code for .Net 4 ? In .Net 4, code can't change the width of column !Medlock
Doesn't do anything in .NET 4.0.Donavon
This worked fine for me, however note that both selecting the object, and resizing the control, will re-apply the 50:50. You'll need to call SetLabelColumnWidth() after each object selection, and resize, in order to maintain it.Docilu
Using reflection to access private internals of a framework control is a terrible idea. There's no way of knowing when this will break. Hell, even a security update to the framework could break this, meaning your application could break after a Windows Update is installed. Encapsulation exists for a reason. Don't poke inside of things.Geisel
S
16

I found that the solution of hamed doesn't work reliably. I have solved it by programmatically simulating the user dragging the column splitter. The following code uses reflection to do this:

public static void SetLabelColumnWidth(PropertyGrid grid, int width)
{
    if(grid == null)
        return;

    FieldInfo fi = grid.GetType().GetField("gridView", BindingFlags.Instance | BindingFlags.NonPublic);
    if(fi == null)
        return;

    Control view = fi.GetValue(grid) as Control;
    if(view == null)
        return;

    MethodInfo mi = view.GetType().GetMethod("MoveSplitterTo", BindingFlags.Instance | BindingFlags.NonPublic);
    if(mi == null)
        return;
    mi.Invoke(view, new object[] { width });
}
Sherr answered 23/1, 2013 at 8:28 Comment(7)
Works but has to be called after the form was built (in Form_Load event or later).Overtask
This does work, but it needs to be called when the PropertyGrid is already visible, not just loaded. I've bound this code to the Resize event, which occurs after showing the control by a button click.Donavon
You can shorten this quite a bit using the new C# 6 null-propagation syntax: pastebin.com/3TEHBPYsWaverly
How did you find the name of the method "MoveSplitterTo" ? I am thinking how can I make the label column to always fit contents. @SherrLunar
I used reflector to see how the splitter was handled in the PropertyGrid.Sherr
In a Framework 3.5 app, this didn't work for me. GetField on gridView returns null.Zygodactyl
Works on Net.4.7 !Soyuz
S
9

2019 Answer

Other answers on this page contain adhoc improvements over the course of C# versions and user comments.

I picked the best working solution and created an Extension method.

public static class PropGridExtensions
{
    public static void SetLabelColumnWidth(this PropertyGrid grid, int width)
    {
        FieldInfo fi = grid?.GetType().GetField("gridView", BindingFlags.Instance | BindingFlags.NonPublic);
        Control view = fi?.GetValue(grid) as Control;
        MethodInfo mi = view?.GetType().GetMethod("MoveSplitterTo", BindingFlags.Instance | BindingFlags.NonPublic);
        mi?.Invoke(view, new object[] { width });
    }
}

Usage:

In Form_Load() event, call it directly on your property grid like so:

myPropertyGrid.SetLabelColumnWidth(value);

You shouldn't need to call it anywhere else. Call once and enjoy.

Sheng answered 8/10, 2019 at 1:17 Comment(0)
Q
4

As in this answer is mentioned :

There is no property to do that and you have to hack the control. first add this code :

    public static void SetLabelColumnWidth(PropertyGrid grid, int width)
{
    if (grid == null)
        throw new ArgumentNullException("grid");

    // get the grid view
    Control view = (Control)grid.GetType().GetField("gridView", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(grid);

    // set label width
    FieldInfo fi = view.GetType().GetField("labelWidth", BindingFlags.Instance | BindingFlags.NonPublic);
    fi.SetValue(view, width);

    // refresh
    view.Invalidate();
}

and call it with the size what you want . like this:

SetLabelColumnWidth(propertyGrid1, 100);
Quartering answered 16/9, 2012 at 14:3 Comment(6)
Field name "labelWidth" not exist! Still, size is 50:50!Medlock
I use .Net 4.5 in my project and there is no problem with code.Quartering
How can I change code for .Net 4 ? In .Net 4, code can't change the width of column !Medlock
Doesn't do anything in .NET 4.0.Donavon
This worked fine for me, however note that both selecting the object, and resizing the control, will re-apply the 50:50. You'll need to call SetLabelColumnWidth() after each object selection, and resize, in order to maintain it.Docilu
Using reflection to access private internals of a framework control is a terrible idea. There's no way of knowing when this will break. Hell, even a security update to the framework could break this, meaning your application could break after a Windows Update is installed. Encapsulation exists for a reason. Don't poke inside of things.Geisel
S
2

Version for Framework 4.0 (I had to use BaseType). Method is used in class inherited from PropertyGrid:

private void SetLabelColumnWidth(int width)
{
    FieldInfo fi = this.GetType().BaseType.GetField("gridView", BindingFlags.Instance | BindingFlags.NonPublic);
    object view = fi.GetValue(this);
    MethodInfo mi = view.GetType().GetMethod("MoveSplitterTo", BindingFlags.Instance | BindingFlags.NonPublic);

    mi.Invoke(view, new object[] { width });
}
Sevik answered 13/5, 2015 at 4:37 Comment(0)
J
0

I've had success with the open source extended PropertyGrid you can find at http://www.codeproject.com/Articles/13630/Add-Custom-Properties-to-a-PropertyGrid. It has two methods you'd be interested in:

AutoSizeProperties - Move automatically the splitter to better fit all the properties shown. MoveSplitterTo - Move the splitter as indicated by the user in the parameter.

You could calculate 25% of the Width of the PropertyGrid and set MoveSplitterTo with it.

I actually use AutoSizeProperties though, as it automatically moves the splitter to snuggly fit the labels. Note that you need to set AutoSizeProperties after you set the SelectedObject.

Jocosity answered 16/9, 2012 at 15:36 Comment(0)
A
0

Since getting the field gridView didn't work for me, I made another approach, where you can get the GridView from the Controls property.

The GridView, however, is of type System.Windows.Forms.PropertyGridInternal.PropertyGridView, which is, you guessed it, internal.

But, all we care about at this point is a control that actually has the method MoveSplitterTo, so we enumerate the controls until we get what we want, and then just call the method.

    public class PropertyGridEx : PropertyGrid
    {
        private int splitterPosition;
        public int SplitterPosition
        {
            get => splitterPosition;
            set
            {
                splitterPosition = value;

                foreach (var control in Controls)
                {
                    if (control.GetType().GetMethod("MoveSplitterTo", BindingFlags.Instance | BindingFlags.NonPublic) is MethodInfo method)
                    {
                        method.Invoke(control, new object[] { value });
                        break;
                    }
                }
            }
        }
    }
Appenzell answered 28/11, 2023 at 18:7 Comment(0)
P
-1

A special use case, that might be useful for someone: I'm using PropertyGrid with a DesignSurface and label column width is narrowing by every value edit. To keep the label column width as the user has set it before the following worked for me:

public UcPropertyGridHost(...)
        {
            ...
            propGrid.PropertyValueChanged += OnPropertyValueChanged;
        }

private void OnPropertyValueChanged(object p_s, PropertyValueChangedEventArgs p_e)
        {
            var iWidth = GetLastLabelWidth();

            //do other things you want to

            SetLabelColumnWidth(propGrid, (int)iWidth);
        }

private int GetLastLabelWidth()
        {
            var iDefaultLabelColumnWidth = propGrid.Width / 2;

            var oFieldInfo = propGrid.GetType().GetField("gridView", BindingFlags.Instance | BindingFlags.NonPublic);
            if (oFieldInfo == null) return iDefaultLabelColumnWidth;

            if (!(oFieldInfo.GetValue(propGrid) is Control oView)) return iDefaultLabelColumnWidth;

            var oFileInfo = oView.GetType().GetField("labelWidth", BindingFlags.Instance | BindingFlags.NonPublic);
            if (oFileInfo == null) return iDefaultLabelColumnWidth;

            return (int)oFileInfo.GetValue(oView);
        }

and the code taken from here:

private void SetLabelColumnWidth(PropertyGrid p_oGrid, int p_iWidth)
    {
        if (p_oGrid == null) return;

        var oFieldInfo = p_oGrid.GetType().GetField("gridView", BindingFlags.Instance | BindingFlags.NonPublic);
        if (oFieldInfo == null) return;

        if (!(oFieldInfo.GetValue(p_oGrid) is Control oView)) return;

        var oMethodInfo = oView.GetType().GetMethod("MoveSplitterTo", BindingFlags.Instance | BindingFlags.NonPublic);
        if (oMethodInfo == null) return;

        oMethodInfo.Invoke(oView, new object[] { p_iWidth });
    }
Pantheas answered 4/5, 2020 at 12:16 Comment(2)
Not functional code (missing reference and information about "oView").Messinger
@Messinger are you really criticising my answer because of the code I took from this thread AND I stated it? BTW, the "..." part of the UcPropertyGridHost is not working code either. I suggest you read the accepted answer to find the same code block that you do not like in my answer.Pantheas
Q
-3

you can use Smart PropertyGrid.Net instead of propertygrid and change the ratio with this code:

propertyGrid1.LabelColumnWidthRatio = 0.25;
Quartering answered 16/9, 2012 at 15:16 Comment(1)
Please guess to me free component!Medlock

© 2022 - 2024 — McMap. All rights reserved.