2013-07-10 2 views
7

のプロパティをソートする場合PropertyGridのは、それが複数選択されたオブジェクトのプロパティをソートするとき.NET FormsPropertyGridDisplayNameAttributeを尊重作るための方法がありますDisplayNameAttributeを無視するフォーム。 1つのオブジェクトがDisplayNameAttributeに基づいてPropertyGridのソートを選択すると、複数のオブジェクトが選択されているときは、実際のプロパティ名を使用してソートされます。.NETは、複数の選択されたオブジェクト

次のコードは、問題を示しています

static class Program 
{ 
    [STAThread] 
    static void Main() 
    { 
     Form myForm1 = new Form(); 
     myForm1.Width = 820; 
     myForm1.Height = 340; 

     PropertyGrid grid1 = new PropertyGrid(); 
     grid1.Left = 0; 
     grid1.Top = 0; 
     grid1.Width = 400; 
     grid1.Height = 300; 
     myForm1.Controls.Add(grid1); 

     grid1.SelectedObject = new MyObject(); 

     PropertyGrid grid2 = new PropertyGrid(); 
     grid2.Left = 400; 
     grid2.Top = 0; 
     grid2.Width = 400; 
     grid2.Height = 300; 
     myForm1.Controls.Add(grid2); 

     object[] objects = new object[] { new MyObject(), new MyObject() }; 
     grid2.SelectedObjects = objects; 

     Application.Run(myForm1); 
    } 
} 


public class MyObject 
{ 
    [DisplayName("ZZZZ")] 
    public int AProperty 
    { 
     get; 
     set; 
    } 

    [DisplayName("BBBB")] 
    public int BProperty 
    { 
     get; 
     set; 
    } 

} 

以前のコードでは、 PropertyGridsFormになります。左グリッドには選択範囲内に単一のオブジェクトが含まれ、右グリッドには選択範囲内に2つのオブジェクトが含まれます。

enter image description here

すべてのオブジェクトは、同じタイプのものです。左グリッドは、に基づいてpropertiesに基づいており、実際のプロパティ名に基づいて右側にソートされています。 をソートするとき

私はPropertyGridは常にDisplayNameAttributeを使用することができます:プロパティがグリッドに名前としてどちらの場合もDisplayNameAttributeが提示されますか?

+0

うわー、Microsoftが.....アルファベット順のソートを表示するポイントは何に基づいて発生します並べ替え、DisplayNameEnforcingConverterMyObjectクラス属性場合...表示された名前をソートしていない場合は? これを行う方法があるはずです。 – 00jt

答えて

2

私は私の問題に対する答えを見つけました。はい、 "force"、またはおそらくより正確に "trick"、PropertyGridはソート時に常にDisplayNameを尊重することができます。この問題の中心は、選択された複数のオブジェクトのプロパティをソートする際に、実際のプロパティ名を使用していることです。だから、望ましい振る舞いを得るためには、DisplayNameが実際のプロパティ名であるとグリッドに信じさせなければなりません。 PropertyGridは、PropertyDescriptorsを使用して、オブジェクトプロパティのさまざまな属性を検出します。実際のプロパティ名としてDisplayNameを表示するカスタムPropertyDescriptorが必要です。次のコードを見よ:以前のクラスは、既存のPropertyDescriptorをラップし、「名前」プロパティの動作を上書きするために使用される

public class DisplayNameEnforcingDescriptor : PropertyDescriptor 
{ 
    private PropertyDescriptor _descriptor; 
    public DisplayNameEnforcingDescriptor(PropertyDescriptor descriptor) 
     : base(descriptor) 
    { 
     this._descriptor = descriptor; 
    } 

    public override string Name 
    { 
     get 
     { 
      return string.IsNullOrEmpty(DisplayName) ? base.Name : DisplayName; 
     } 
    } 

    public override bool CanResetValue(object component) 
    { 
     return _descriptor.CanResetValue(component); 
    } 

    public override Type ComponentType 
    { 
     get 
     { 
      return _descriptor.ComponentType; 
     } 
    } 

    public override object GetValue(object component) 
    { 
     return _descriptor.GetValue(component); 
    } 

    public override bool IsReadOnly 
    { 
     get 
     { 
      return _descriptor.IsReadOnly; 
     } 
    } 

    public override Type PropertyType 
    { 
     get 
     { 
      return _descriptor.PropertyType; 
     } 
    } 

    public override void ResetValue(object component) 
    { 
     _descriptor.ResetValue(component); 
    } 

    public override void SetValue(object component, object value) 
    { 
     _descriptor.SetValue(component, value); 
    } 

    public override bool ShouldSerializeValue(object component) 
    { 
     return _descriptor.ShouldSerializeValue(component); 
    } 
} 

NameプロパティはDisplayName(ヌルまたは空でない場合)または実際のプロパティ名を返します。他のすべての機能はラップされたPropertyDescriptorに委譲されます。

ここで提示されたプロパティ名を変更するには、PropertyGridに新しいPropertyDescriptorを使用するだけです。これを行うには、カスタマイズされたTypeDescriptorが必要です。その既存の動作を活用し、当社の実装を最小限に抑えるためにExpandableObjectConverterから

public class DisplayNameEnforcingConverter : ExpandableObjectConverter 
{ 
    public override PropertyDescriptorCollection GetProperties(ITypeDescriptorContext context, object value, Attribute[] attributes) 
    { 
     PropertyDescriptorCollection original = base.GetProperties(context, value, attributes); 
     List<DisplayNameEnforcingDescriptor> descriptorList = new List<DisplayNameEnforcingDescriptor>(); 
     foreach (PropertyDescriptor descriptor in original) 
      descriptorList.Add(new DisplayNameEnforcingDescriptor(descriptor)); 
     return new PropertyDescriptorCollection(descriptorList.ToArray()); 
    } 
} 

このクラスは継承:もう一度、次のコードを見よ。 GetPropertiesメソッドをオーバーライドするだけで済みます。このメソッドは、基底型に関連性を取得するように求めます。PropertyDescriptorCollectionは、このコレクションのすべての要素をDisplayNameEnforcingDescriptorにラップします。ラップされた要素を含む新しいcollectionが返されます。

今、私たちは常にプロパティDisplayName

[TypeConverter(typeof(DisplayNameEnforcingConverter))] 
public class MyObject 
{ 
    [DisplayName("ZZZZ")] 
    public int AProperty 
    { 
     get; 
     set; 
    } 

    [DisplayName("BBBB")] 
    public int BProperty 
    { 
     get; 
     set; 
    } 
} 

enter image description here

0

PropertyGrid.PropertySortOrder状態のドキュメント:カスタムの並べ替えを行うには

、所望の順序でプロパティを返すために、コンポーネント にICustomTypeDescriptorを実装します。

私はICustomTypeDescriptorを実装するクラスを変更し、ICustomTypeDescriptorメソッドが呼び出さ取得し、属性DisplayName順にプロパティを返した、PropertyGrid.SelectObjectsはまだ実際のプロパティ名でソートを主張しながら:

public class MyObject : ICustomTypeDescriptor 
{ 
    [DisplayName("ZZZZ")] 
    public int AProperty 
    { 
     get; 
     set; 
    } 

    [DisplayName("BBBB")] 
    public int BProperty 
    { 
     get; 
     set; 
    } 

    public PropertyDescriptorCollection GetProperties() 
    { 
     // Creates a new collection and assign it the properties for button1. 
     var properties = TypeDescriptor.GetProperties(this) 
          .OfType<PropertyDescriptor>(); 
     var result = properties.OrderBy(x => x.DisplayName); 
     return new PropertyDescriptorCollection(result.ToArray()); 
    } 

    public PropertyDescriptorCollection GetProperties(Attribute[] attributes) 
    { 
     var properties = TypeDescriptor.GetProperties(this, attributes, true) 
          .OfType<PropertyDescriptor>(); 
     var result = properties.OrderBy(x => x.DisplayName); 
     return new PropertyDescriptorCollection(result.ToArray()); 
    } 

    public AttributeCollection GetAttributes() 
    { 
     return TypeDescriptor.GetAttributes(this, true); 
    } 

    public string GetClassName() 
    { 
     return TypeDescriptor.GetClassName(this, true); 
    } 

    public string GetComponentName() 
    { 
     return TypeDescriptor.GetComponentName(this, true); 
    } 

    public TypeConverter GetConverter() 
    { 
     return TypeDescriptor.GetConverter(this, true); 
    } 

    public EventDescriptor GetDefaultEvent() 
    { 
     return TypeDescriptor.GetDefaultEvent(this, true); 
    } 

    public PropertyDescriptor GetDefaultProperty() 
    { 
     return TypeDescriptor.GetDefaultProperty(this, true); 
    } 

    public object GetEditor(Type editorBaseType) 
    { 
     return TypeDescriptor.GetEditor(this, editorBaseType, true); 
    } 

    public EventDescriptorCollection GetEvents(Attribute[] attributes) 
    { 
     return TypeDescriptor.GetEvents(this, attributes, true); 
    } 

    public EventDescriptorCollection GetEvents() 
    { 
     return TypeDescriptor.GetEvents(this, true); 
    } 

    public object GetPropertyOwner(PropertyDescriptor pd) 
    { 
     return this; 
    } 
} 

これは機能しないので、あなたの質問に対する答えは、いいえ、PropertyGridを複数のオブジェクトを選択するときにDisplayNameAttributeにソートすることはできません。

関連する問題