14

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.

Vikdor
  • 23,934
  • 10
  • 61
  • 84
Ali Ahmadi
  • 2,387
  • 4
  • 31
  • 48

7 Answers7

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 });
}
Nic
  • 161
  • 1
  • 4
7

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.

JamesHoux
  • 2,999
  • 3
  • 32
  • 50
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);
Community
  • 1
  • 1
Hamed
  • 2,084
  • 6
  • 22
  • 42
  • 1
    Field name "labelWidth" not exist! Still, size is 50:50! – Ali Ahmadi Sep 16 '12 at 14:18
  • 1
    I use .Net 4.5 in my project and there is no problem with code. – Hamed Sep 16 '12 at 14:38
  • How can I change code for .Net 4 ? In .Net 4, code can't change the width of column ! – Ali Ahmadi Sep 16 '12 at 14:40
  • Doesn't do anything in .NET 4.0. – ygoe Sep 20 '14 at 22:59
  • 1
    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. – Memetican Sep 05 '18 at 21:36
  • 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. – MetaFight Sep 25 '21 at 20:01
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 });
}
Oswald
  • 1,252
  • 20
  • 32
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.

Stephen Swensen
  • 22,107
  • 9
  • 81
  • 136
0

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 });
    }
tretom
  • 559
  • 1
  • 7
  • 17
-3

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

propertyGrid1.LabelColumnWidthRatio = 0.25;
Hamed
  • 2,084
  • 6
  • 22
  • 42