Eric Anastas
Eric Anastas

Reputation: 22213

Resetting properties from a property grid

I am using a PropertyGrid to show properties from my objects. However, I'm also allowing the user to create their own properties, and set values for these custom properties. Each object that can have these custom properties has a Dictionary collection, where the string is a unique key to identify the property, and Object is the value of a primitive type (string, bool, int etc..)

I've created a custom PropertyDescriptor with get and set methods that check the Dictionary for a matching key, or create/overwrite the value with a matching key respectively.

However, I also want to give the user the ability to clear the property, and thus remove its entry from the dictionary entirely. I'd put the code to to this in the ResetValue override method of my custom PropertyDescriptor, however I don't see any way through the PropertyGrid interface to envoke this? It doesn't seem to be a context menu option or something obvious like that.

So if I have a custom PropertyDescriptor with a custom ResetValue method, how do I actually evoke that method from a PropertyGrid?

Upvotes: 6

Views: 5098

Answers (4)

SubqueryCrunch
SubqueryCrunch

Reputation: 1495

This is what i am using to reset my properties

    public static void InitResetContextMenuStrip(this PropertyGrid grid, params string[] resettableProperties)
    {
        if (grid.ContextMenuStrip != null)
            return;

        var menuStrip = new ContextMenuStrip();
        var resetItem = new ToolStripMenuItem("Reset");

        resetItem.Click += (s, e) =>
        {
            try
            {
                if (resettableProperties.Any(p => grid.SelectedGridItem.PropertyDescriptor.Name == p))
                {
                    grid.SelectedGridItem.PropertyDescriptor.SetValue(grid.SelectedObject, null);
                    grid.Refresh(); //redraw the grid to reflect the changes
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        };

        menuStrip.Items.Add(resetItem);

        menuStrip.Opening += (s, e) =>
        {
            try
            {
                resetItem.Enabled = resettableProperties.Any(p => grid.SelectedGridItem.PropertyDescriptor.Name == p);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        };

        grid.ContextMenuStrip = menuStrip;
    }

And this is how i use it:

myGrid.InitResetContextMenuStrip(
    nameof(ClassName.PropertyName1),
    nameof(ClassName.PropertyName2));

Credit: http://www.windows-tech.info/3/41955b2a405bf481.php

Upvotes: 0

Serge N
Serge N

Reputation: 104

For child objects the reference to the object containing a property is hidden in the Instance property of the non-public descendants of the GridItem class. Thankfully, this property is a member of the ITypeDescriptorContext interface which these descendant classes do implement. So, there is a solution that includes correct enabling of the Reset command in a context menu for all properties:

private void contextMenuToolStrip_Opening(object sender, CancelEventArgs e)
{
  var item = propertyGrid.SelectedGridItem;
  resetToolStripMenuItem.Enabled = item != null &&
                                   item.GridItemType == GridItemType.Property &&
                                   item is ITypeDescriptorContext context &&
                                   item.PropertyDescriptor.CanResetValue(context.Instance);
}

private void resetToolStripMenuItem_Click(object sender, EventArgs e)
{
  propertyGrid.ResetSelectedProperty();
}

Upvotes: 1

Donald Peter
Donald Peter

Reputation: 21

Annotation: The PropertyGrid.SelectedObject returns the wrong Value (component) in Childobjects. Consequently the Method CanResetValue recived a incorrect component.

My Solution:

private void OnContextMenuOpening(object sender, CancelEventArgs e)
{
  var lGrid = mCurrentControl as PropertyGrid;

  if (lGrid != null)
  {
    var lItem = lGrid.SelectedGridItem;

    // Für untergeordnete Eigenschaften kann nicht SelectedObject verwendet werden
    // Component ist eine interne Eigenschaft der Klasse System.Windows.Forms.PropertyGridInternal.GridEntry
    // ((System.Windows.Forms.PropertyGridInternal.GridEntry)(lItem)).Component
    // Zugriff via Reflection
    var lComponent = lItem.GetType().GetProperty("Component").GetValue(lItem, null);

    if (lComponent != null)
      tsmi_Reset.Enabled = lItem.PropertyDescriptor.CanResetValue(lComponent);
    else
      tsmi_Reset.Enabled = lItem.PropertyDescriptor.CanResetValue(lGrid.SelectedObject);
  }
}

// Contextmenu -> Reset
private void OnResetProperty(object sender, EventArgs e)
{
  var lGrid = mCurrentControl as PropertyGrid;

  if (lGrid != null)
    lGrid.ResetSelectedProperty();
}

Upvotes: 2

Daniel LeCheminant
Daniel LeCheminant

Reputation: 51071

I think the easiest way to achieve this is to add a contextmenu to your property grid, with a menu item "Reset", and then handling its click event like this:

private void resetToolStripMenuItem_Click(object sender, EventArgs e)
{                        
    PropertyDescriptor pd = propGrid.SelectedGridItem.PropertyDescriptor;
    pd.ResetValue(propGrid.SelectedObject);
}

I think Visual Studio does something like this.

Upvotes: 3

Related Questions