【问题标题】:PropertyGrid doesn't notice properties changed in code?PropertyGrid 没有注意到代码中的属性发生了变化?
【发布时间】:2012-04-22 22:40:34
【问题描述】:

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

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

但是,似乎虽然它设置了我的对象的属性,但属性网格并没有改变。如果在重置后,我做了一个属性网格“刷新”,它具有重置颜色。

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

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

谢谢

(非常相似的问题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"));
  }
}

从我的评论 “没有订阅 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();
  }
}

【问题讨论】:

    标签: c# winforms data-binding inotifypropertychanged propertygrid


    【解决方案1】:

    要回答您关于 PropertyGrid 为何不改变的问题,PropertyGrid 的 MSDN 文档这样说:

    网格中显示的信息是属性的快照 在分配对象时。如果对象的一个​​属性值 由 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();
    }
    

    【讨论】:

    • 嗨,谢谢,这几乎是我已经拥有的。我更感兴趣的是为什么属性网格本身没有注意到属性已经改变。没有任何东西(即 PropertyGrid 控件)订阅“PropertyChanged”事件。当然......我可以自己做,就像你一样,但是为什么呢?难道是PropertyGrid控件没有绑定属性,所以不监听INotifyPropertyChanged事件?
    【解决方案3】:

    在试图记住我曾经使用过的东西并认为它可能对其他人有用的过程中发生了这个问题。

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

    例如:

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

    【讨论】:

    • 这对我有用,只需要添加对 System.ComponentModel 的引用。比乱用代码强制刷新要好得多。
    【解决方案4】:

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

    【讨论】:

    • 这是一种奇怪的回答方式。你确实试图回答这个问题,不是吗?
    【解决方案5】:

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

    请注意,这种情况无需调用 collapse 方法。

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

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

    【讨论】:

      猜你喜欢
      • 2019-05-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-06-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多