4

I have a PropertyGrid whose selected object contains multiple properties with [DisplayName]s of "Speed", all in different categories (the real property names in the code are of course all unique). I've noticed that if I have (for example) Speed #3 selected and PropertyGrid.Refresh() is called, the selection will automatically move to Speed #1. What's more, the value of Speed #3 will sometimes be shown next to Speed #1 too. The situation resolves itself as soon as I click the grid and change the selection, but it's obviously not desired behavior.

I am currently hacking around this by adding different numbers of \t characters to the DisplayNames to make them all unique. This is an acceptable workaround since the tab characters aren't actually rendered, but I'd of course prefer not to have to do it.

Is there a rule that all DisplayNames must be unique or is this a bug in PropertyGrid?


Update: Since someone's bound to ask for a code sample, stick one of these in a PropertyGrid and then call Refresh() on it from a timer every two seconds or so:

class Demo
{
    [Category("Cat1")]
    [DisplayName("Speed")]
    public int Speed1 { get; set; }

    [Category("Cat2")]
    [DisplayName("Speed")]
    public int Speed2 { get; set; }

    [Category("Cat3")]
    [DisplayName("Speed")]
    public int Speed3 { get; set; }
}
dlf
  • 9,045
  • 4
  • 32
  • 58

1 Answers1

2

I don't think it's a bug, it's probably a feature (with side effects :-). You can check the property grid source on Microsoft site. The relevant portion seems this in GridEntry.cs code:

public override bool Equals(object obj) {
  if (NonParentEquals(obj)) {
    return((GridEntry)obj).ParentGridEntry == this.ParentGridEntry;
  }
  return false;
}

internal virtual bool NonParentEquals(object obj) {
  if (obj == this) return true;
  if (obj == null) return false;
  if (!(obj is GridEntry)) return false;
  GridEntry pe = (GridEntry)obj;

  return pe.PropertyLabel.Equals(this.PropertyLabel) &&
    pe.PropertyType.Equals(this.PropertyType) && pe.PropertyDepth == this.PropertyDepth;
}

As you see, it's the PropertyLabel which is used. If you follow the code a bit more, the label will ultimately use the property's DisplayName (or the name if the DisplayName attribute is not defined).

Simon Mourier
  • 132,049
  • 21
  • 248
  • 298
  • That certainly does seem to explain why it happens. But... `GridEntry` has an overridable `PropertyDescriptor` attribute. It seems like that could be leveraged here if it returns nonnull, or that `PropertyDescriptorGridEntry` could override `NonParentEquals` to add that check, but who knows. Whatever the case, it does seem to show that there is an unwritten (as far as I know) rule that each property you expose in the grid needs to have a unique combination of display name, type, and tree depth. – dlf Aug 12 '14 at 12:22
  • The GridEntry we see are in fact PropertyDescriptorGridEntry which are bound to a specific PropertyDescriptor, plus all this is internal, so, there's not way to change this unless with big big hacks... – Simon Mourier Aug 12 '14 at 12:37
  • Right; I was just wondering why the original developers didn't do one of those things in the first place. But it's obviously moot now; at least I have a workaround! – dlf Aug 12 '14 at 12:40