PropertyGrid 不会注意到代码中更改的属性

本文关键字:属性 代码 注意到 PropertyGrid | 更新日期: 2023-09-27 18:30:49

我有一个Winform应用程序,它使用颜色来突出显示某些内容。我想允许用户更改"他们的"颜色。作为练习,我想我会创建一个类的实例,其中包含颜色的属性,并将其分配给属性网格(以获得一个不错的编辑器)。

这似乎工作正常,但我想让用户重置颜色(在他们摆弄并将它们设置为 20 种米色之后)。因此,我在窗体中添加了一个"重置"按钮,该按钮将对象的颜色属性设置回默认值。

但是,似乎虽然它设置了对象的属性,但属性网格不会更改。如果在重置后,我执行属性网格"刷新",它具有重置颜色。

我假设属性网格不知道基础对象已更改?

在这种情况下是否缺少某些内容,或者我应该接受它并在重置对象时调用 Refresh 方法?

谢谢

(这里非常相似的问题)

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

PropertyGrid 不会注意到代码中更改的属性

为了回答您关于为什么 PropertyGrid 不更改的问题,PropertyGrid 的 MSDN 文档是这样说的:

网格中显示的信息是属性的快照 在分配对象时。如果对象的属性值 由 SelectedObject 指定的对象在运行时在代码中更改,即 在网格中执行操作之前,不会显示新值 导致网格刷新。

因此,似乎 PropertyGrid 不是一个可自动更新的控件。 我认为这方面的线索是 PropertyGrid 使用 SelectedObject 方法而不是 DataSource 方法,后者意味着它可能侦听 INotifyPropertyChanged。

您只剩下LarsTech的建议并手动刷新网格。

只需尝试刷新它:

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

假设您将拥有更多属性,则可以使用 PropertyChanged 事件。 我会像这样修改你的颜色类:

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

在试图记住我过去使用的东西并认为它可能对其他人有用时遇到了这个问题。

您可以使用 [刷新属性] 属性来触发对属性网格的更新。

例如:

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

使用 DotNetBar AdvPropertyGrid 控件。您不需要任何iNotify调用即可更新它。
每当任何对象属性更改时,它都会自动更新网格。

在 .Net 4.7.2 项目中,我发现调用 yourPropGridInstanceHere.ExpandAllGridItems() 会导致属性网格根据当前的"SelectedObject"刷新其值。

请注意,无需调用折叠方法即可发生这种情况。

当然,如果您折叠了一些类别,这可能对您不起作用,但至少在更简单的情况下,它不必实现INotifyPropertChanged或必须不断更新SelectedObject属性。

我还没有用任何其他 .Net 版本对此进行测试,但我怀疑它会适用于所有版本。