PropertyGrid не замечает изменений, измененных в коде?

У меня есть приложение Winform, которое использует цвет, чтобы выделить некоторые вещи. Я бы хотел, чтобы пользователи меняли "свои" цвета. В качестве упражнения я решил создать экземпляр класса со свойствами для цветов и назначить его сетке свойств (чтобы получить хороший редактор).

Кажется, что все нормально, но я подумал, что хотел бы позволить пользователям reset цвета (после того, как они поиграли и установили их на 20 оттенков бежевого). Итак, я добавил кнопку "reset" в мою форму, которая вернула свойства цвета моего объекта по умолчанию.

Однако кажется, что, пока он возвращает мои свойства объекта, сетка свойств не изменяется. Если после reset я создаю сетку свойств "Обновить", она имеет цвет reset.

Я предполагаю, что сетка свойств не знает, что базовый объект был изменен?

Есть ли что-то в этом сценарии или я должен просто принять его и вызвать метод Refresh, когда я reset мой объект?

Спасибо

(очень похожий вопрос здесь)

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"));
  }
}

Вслед за моим комментарием "ничего не подписывается на INotifyPropertyChanged.PropertyChanged", какой недостаток заключается в подклассификации элемента управления PropertyGrid, чтобы он это сделал?

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();
  }
}

Ответ 1

Чтобы ответить на вопрос о том, почему PropertyGrid не изменяется, в документации MSDN для PropertyGrid говорится следующее:

Информация, отображаемая в сетке, представляет собой снимок свойств в момент назначения объекта. Если значение свойства объекта указанный в элементе SelectedObject, изменен в коде во время выполнения, новое значение не отображается до тех пор, пока в сетке не будет выполнено действие, которое вызывает обновление сетки.

Итак, похоже, что PropertyGrid не является автоматическим обновлением. Я думаю, что ключ к этому заключается в том, что PropertyGrid использует метод SelectedObject вместо метода DataSource, а последний подразумевает, что он, вероятно, прослушивает INotifyPropertyChanged.

Осталось то, что предложил LarsTech, и вручную обновляя сетку.

Ответ 2

Просто попробуйте обновить его:

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

Предполагая, что у вас будет больше свойств, вы можете использовать событие PropertyChanged. Я бы изменил ваш класс Color следующим образом:

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");
    }
  }
}

Тогда ваша форма будет выглядеть так:

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();
}

Ответ 3

Произошел этот вопрос, пытаясь вспомнить, что я использовал, и подумал, что это может быть полезно другим.

Вы можете использовать атрибут [RefreshProperties] для запуска обновлений в Property Grid.

например:

    [RefreshProperties(RefreshProperties.All)]
    public int MyProperty{ get; set; }

Ответ 4

Используйте элемент управления DotNetBar AdvPropertyGrid. Вам не нужен вызов iNotify для его обновления.
Он автоматически обновляет сетку всякий раз, когда изменяется любое свойство объекта.