PropertyGrid doesn't notice properties changed in code?
Asked Answered
L

5

14

I have a Winform application which uses colour to highlight certain things. I would like to allow the users to change 'their' colours. As an exercise, I thought I would create an instance of a class, with properties for the colours, and assign it to a property grid (to get a nice editor).

This seems to work fine, but I then thought I would like to let the users reset the colours (after they had fiddled and set them to 20 shades of beige). So, I added a "reset" button to my form, which set the colour properties of my object back to the defaults.

However, it seems that while it sets my object's properties back, the property grid doesn't change. If, after the reset, I do a property grid "Refresh", it has the reset colour.

I'm assuming that the property grid doesn't know that the underlying object has been changed ?

Is there something missing in this scenario, or should I just accept it and call the Refresh method when I reset my object ?

Thanks

(very similar question here)

public partial class Form1 : Form
{
  public Form1()
  {
     InitializeComponent();

     this.propertyGrid1.SelectedObject = new Colours();
  }

  private void button1_Click(object sender, EventArgs e)
  {
     Colours colours = this.propertyGrid1.SelectedObject as Colours;
     colours.Reset();
  }
}

public partial class Colours : INotifyPropertyChanged 
{
  public event PropertyChangedEventHandler PropertyChanged;

  public Color ColourP1 { get; set; }

  public void Reset()
  {
     this.ColourP1 = Color.Red;
     var handler = this.PropertyChanged;
     if (handler != null) handler(this, new PropertyChangedEventArgs("ColourP1"));
  }
}

Following on from my comment of "nothing subscribes to the INotifyPropertyChanged.PropertyChanged", what's the drawback in subsclassing the PropertyGrid control so that it does ?

public partial class MyPropertyGrid : System.Windows.Forms.PropertyGrid
{
  private INotifyPropertyChanged _selectedObject;

  protected override void OnSelectedObjectsChanged(EventArgs e)
  {
     base.OnSelectedObjectsChanged(e);

     if (_selectedObject != null) _selectedObject.PropertyChanged -= selectedObject_PropertyChanged;
     _selectedObject = this.SelectedObject as INotifyPropertyChanged;
     if (_selectedObject != null) _selectedObject.PropertyChanged += selectedObject_PropertyChanged;
  }

  private void selectedObject_PropertyChanged(object sender, PropertyChangedEventArgs e)
  {
     this.Refresh();
  }
}
Laugh answered 10/4, 2012 at 15:56 Comment(0)
S
15

To answer your question on why the PropertyGrid doesn't change, the MSDN documentation for the PropertyGrid say this:

The information displayed in the grid is a snapshot of the properties at the time the object is assigned. If a property value of the object specified by the SelectedObject is changed in code at run time, the new value is not displayed until an action is taken in the grid that causes the grid to refresh.

So, it seems that the PropertyGrid is not a control that is auto-updatable. I think the clue to this is that the PropertyGrid uses the SelectedObject method instead of a DataSource method, and the latter would imply it probably listens to INotifyPropertyChanged.

You're left with what LarsTech has suggested and manually refreshing the grid.

Showoff answered 12/4, 2012 at 19:8 Comment(1)
Yep, that pretty much sums it up.Smattering
S
11

Just try refreshing it:

private void button1_Click(object sender, EventArgs e)
{
  Colours colours = this.propertyGrid1.SelectedObject as Colours;
  colours.Reset();
  this.propertyGrid1.Refresh();
}

Assuming you will have more properties, you can use your PropertyChanged event. I would modify your Colour class like this:

public class Colours : INotifyPropertyChanged {
  public event PropertyChangedEventHandler PropertyChanged;

  private Color _ColourP1;

  public void Reset() {
    this.ColourP1 = Color.Red;
  }

  private void OnChanged(string propName) {
    if (PropertyChanged != null)
      PropertyChanged(this, new PropertyChangedEventArgs(propName));
  }

  public Color ColourP1 {
    get { return _ColourP1; }
    set {
      _ColourP1 = value;
      OnChanged("ColourP1");
    }
  }
}

Then your form would look like this:

public Form1() {
  InitializeComponent();

  Colours colours = new Colours();
  colours.PropertyChanged += colours_PropertyChanged;
  this.propertyGrid1.SelectedObject = colours;
}

private void colours_PropertyChanged(object sender, PropertyChangedEventArgs e) {
  this.propertyGrid1.Refresh();
}

private void button1_Click(object sender, EventArgs e) {
  ((Colours)this.propertyGrid1.SelectedObject).Reset();
}
Smattering answered 10/4, 2012 at 16:27 Comment(1)
Hi, thanks, that's pretty much what I had already. I was more interested in why the property grid itself doesn't notice that the property has changed. Nothing (ie. the PropertyGrid control) subscribes to the "PropertyChanged" event. Sure... I could do it myself, as you have, but why ? Could it be that the PropertyGrid control has no bound properties, so doesn't listen for the INotifyPropertyChanged event ?Laugh
H
9

Happened across this Question in trying to remember what I used to use and thought it might be useful to others.

You can use the [RefreshProperties] Attribute to trigger updates to the Property Grid.

eg:

    [RefreshProperties(RefreshProperties.All)]
    public int MyProperty{ get; set; }
Harem answered 26/10, 2016 at 15:6 Comment(1)
This worked for me, just had to add a reference to System.ComponentModel. Much better than messing around with code to force a refresh.Corroboration
E
1

In a .Net 4.7.2 project I have found that calling yourPropGridInstanceHere.ExpandAllGridItems() causes the property grid to refresh its values based on the current 'SelectedObject'.

Note that this happens without having to call the collapse method.

Granted, if you have some categories collapsed this may not work for you but at least in the simpler cases it saves from having to implement INotifyPropertChanged or having to constantly update the SelectedObject property.

I haven't tested this with any other .Net versions as yet, but i suspect it will work across all of them.

Exclosure answered 30/8, 2021 at 21:59 Comment(0)
D
0

Use DotNetBar AdvPropertyGrid control. You don't need any iNotify call to update it.
It automatically update grid whenever any object property change.

Disentail answered 24/8, 2019 at 15:7 Comment(1)
That is a strange way of phrasing an answer. You did attempt to answer the question, didn't you?Townsfolk

© 2022 - 2024 — McMap. All rights reserved.