Select a property in the property grid

I am using a PropertyGrid to display the content of an object to the user.

This PropertyGrid is synchronized with an Excel sheet, assuming a cell value match a property value.

As the user selects a property in the PropertyGrid, the application highlights the corresponding cell in the Excel sheet which is opened beside. I can do this using the SelectedGridItemChanged event.

Now, I want to have a property selected in my PropertyGrid when the user selects a cell in the Excel sheet.

void myWorkbook_SheetSelectionChangeEvent(NetOffice.COMObject Sh, Excel.Range Target)
{
    if (eventMask > 0)
        return;

    try
    {
        eventMask++;

        this.Invoke(new Action(() => 
        {
            propertyGrid1.SelectedGridItem = ... // ?
        }
    }
    finally
    {
        eventMask--;
    }
}

I noticed that the SelectedGridItem can be written to.

Unfortunately I do not find a way to access the GridItems collection of my PropertyGrid so I can look for the right GridItem and select it.

How can I do this?

You can get all the GridItems from the root. I am using the below code to retrieve all the griditems within a property grid

private GridItem Root
    {
        get
        {
            GridItem aRoot = myPropertyGrid.SelectedGridItem;
            do
            {
                aRoot = aRoot.Parent ?? aRoot;
            } while (aRoot.Parent != null);
            return aRoot;
        }
    }

and pass the root to the below method

private IList<GridItem> GetAllChildGridItems(GridItem theParent)
    {
        List<GridItem> aGridItems = new List<GridItem>();
        foreach (GridItem aItem in theParent.GridItems)
        {
            aGridItems.Add(aItem);
            if (aItem.GridItems.Count > 0)
            {
                aGridItems.AddRange(GetAllChildGridItems(aItem));
            }
        }
        return aGridItems;
    }

PropertyGrid.SelectedGridItem Property (System.Windows.Forms , The currently selected row in the property grid. Attributes. BrowsableAttribute. Remarks. Each GridItem corresponds to a property of the SelectedObject. You can  It then sets the PropertyGrid control's SelectedGridItem property to that item so it is selected. ' Select ths property grid's indicated item. Public Sub SelectPropertyGridItem(ByVal property_grid As _ PropertyGrid, ByVal item_label As String) property_grid.SelectedGridItem = _ FindPropertyGridItem(property_grid, item_label) End Sub

I came up against this quite a bit a project so I wrote an extension method for it:

if (!SetupManagerSettings.BootStrapperLocation.IsFile()) // Just another extension method to check if its a file
{
    settingsToolStripMenuItem.Checked = true;  // Event handler OnChecked ensures the settings panel is unhidden
    settingsPropertyGrid.ActivateControl();

    settingsPropertyGrid.SelectPropertyGridItemByName("BootStrapperLocation"); // Here is the extension method 

    return false;
}

Here is the extension method with a private, supporting method for traversing the hierarchy of objects (if this applies to your object model):

    public static bool SelectPropertyGridItemByName(this PropertyGrid propertyGrid, string propertyName)
    {
        MethodInfo getPropEntriesMethod = propertyGrid.GetType().GetMethod("GetPropEntries", BindingFlags.NonPublic | BindingFlags.Instance);

        Debug.Assert(getPropEntriesMethod != null, @"GetPropEntries by reflection is still valid in .NET 4.6.1 ");

        GridItemCollection gridItemCollection = (GridItemCollection)getPropEntriesMethod.Invoke(propertyGrid, null);

        GridItem gridItem = TraverseGridItems(gridItemCollection, propertyName);

        if (gridItem == null)
        {
            return false;
        }

        propertyGrid.SelectedGridItem = gridItem;

        return true;
    }

    private static GridItem TraverseGridItems(IEnumerable parentGridItemCollection, string propertyName)
    {
        foreach (GridItem gridItem in parentGridItemCollection)
        {
            if (gridItem.Label != null && gridItem.Label.Equals(propertyName, StringComparison.OrdinalIgnoreCase))
            {                   
                return gridItem;
            }

            if (gridItem.GridItems == null)
            {
                continue;
            }

            GridItem childGridItem = TraverseGridItems(gridItem.GridItems, propertyName);

            if (childGridItem != null)
            {
                return childGridItem;
            }
        }

        return null;
    } 

Selecting Property Views in Microsoft PropertyGrid, The PropertyGrid control supports multiple property views - alphabetical, categorized and others. To switch between different views, the users can select the  ' Select ths property grid's indicated item. Public Sub SelectPropertyGridItem(ByVal property_grid As _ PropertyGrid, ByVal item_label As String) property_grid.SelectedGridItem = _ find_item(property_grid, item_label) End Sub : See also Select a particular property in a PropertyGrid control in Visual Basic .NET.

I looked at the above options and did not like them that much, I altered it a bit found that this works well for me

bool TryFindGridItem(PropertyGrid grid, string propertyName, out GridItem discover)
{
    if (grid is null)
    {
        throw new ArgumentNullException(nameof(grid));
    }

    if (string.IsNullOrEmpty(propertyName))
    {
        throw new ArgumentException("You need to provide a property name", nameof(propertyName));
    }

    discover = null;
    var root = pgTrainResult.SelectedGridItem;
    while (root.Parent != null)
        root = root.Parent;

    foreach (GridItem item in root.GridItems)
    {
        //let's not find the category labels 
        if (item.GridItemType!=GridItemType.Category)
        {
            if (match(item, propertyName))
            {
                discover= item;
                return true;

            }
        }
        //loop over sub items in case the property is a group

        foreach (GridItem child in item.GridItems)
        {
            if (match(child, propertyName))
            {
                discover= child;
                return true;
            }
        }


        //match based on the property name or the DisplayName if set by the user
        static bool match(GridItem item, string name)
            => item.PropertyDescriptor.Name.Equals(name, StringComparison.Ordinal) || item.Label.Equals(name, StringComparison.Ordinal);


    }
    return false;
}

it uses a local method named match, if you're version of C# does not allow it then just put it external to the method and perhaps give it a better name.

Match looks at the DisplayName as well as the property name and returns true if either is a match, this might not be what you would like so then update that.

In my usecase I need to select the property based on a value the user can select so call the above method like this:

if (TryFindGridItem(pgMain, propertyName, out GridItem gridItem))
{                
     gridItem.Select();
}

It could theoretically never not find it unless the user selects a string that is not proper this way the if can be updated using an else .. I rather keep it safe then have a null-pointer exception if I can't find the name specified.

Also I am not going into sub classes and lists of classes as my use case doesn't need that, if yours does than perhaps make recursive calls in the GridItem.

Small note, replace GridItem with var and the code brakes as at compile time the IDE has no clue what a GridItemCollection returns…

HowTo: Select a particular property in a PropertyGrid , This example shows how to select a particular property in a PropertyGrid control in Visual Basic .NET. Keywords, PropertyGrid, property grid, select property, VB. I need to set the selected item of my property grid. I'm getting an eventargs, which stores a string (this string tells me what property in my propertygrid the user wants to select). The problem is i cannot find a collection of grid items, i can select one from.

The PropertyGrid Control, basics, The central part will be occupied by the object's properties, while at the bottom there is a help text on the property that the user has selected in the control. This is​  The property grid can display a context menu for properties. The menu contains the predefined Reset command that sets the property to its default value. You can also provide custom commands by handling dedicated events. To invoke the menu, users can right-click a property or click a brick button (Office view only).

How to: Specify which properties to display in the Property Grid , To control which properties to display in the Property Grid when selecting layout items, a BasePropertyGridObjectWrapper class descendant is  The CMFCPropertyGridCtrl class displays a property grid control that contains editable properties derived from the CMFCPropertyGridProperty class. Each property can represent a type and it can contain subitems. The property grid control supports a resizable area at the bottom that can display the description of a selected property.

Property Grid | WinForms Controls, The PropertyGridControl reveals object properties and allows you to modify them while an application is running. Property Grid - Landing. Select  The grid-column property specifies a grid item's size and location in a grid layout, and is a shorthand property for the following properties: grid-column-start grid-column-end

Comments
  • ... then I can use the PropertyDescriptor property to get the GridItem I want, then I can do a Select(). If only I could upvote twice... The only quirck I had is that my PropertyGrid is empty sometimes so I have to check if a GridItem is selected before applying this. Brilliant! Thank you very much. Indeed. And by the way, welcome to the SO community.