7

複数の選択されたオブジェクトのプロパティを並べ替えるときに.NET Forms PropertyGrid尊重する方法はありますか。DisplayNameAttribute単一のオブジェクトが選択されている場合は、PropertyGridに基づいてソートされDisplayNameAttributeますが、複数のオブジェクトが選択されている場合は、実際のプロパティ名を使用してソートされます。

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

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

}

前のコードはFormwith two PropertyGridsを作成します。左側のグリッドには 1 つのオブジェクトが選択されており、右側のグリッドには 2 つのオブジェクトが選択されています。

ここに画像の説明を入力

すべてのオブジェクトは同じタイプです。左のグリッドは にproperties基づいて並べ替え、DisplayNameAttribute右のグリッドは実際のプロパティ名に基づいて並べ替えます。どちらの場合もDisplayNameAttribute、グリッドにプロパティ名として表示されます。

並べ替え時に常に を使用するように強制できますか?PropertyGridDisplayNameAttribute

4

2 に答える 2

2

だから私は私の問題に対する答えを見つけました。はい、" force"、またはより正確には " trick"、ソート時PropertyGridに常に を尊重することが可能です。DisplayName問題の核心は、「PropertyGrid」が複数の選択されたオブジェクトのプロパティを並べ替えるときに実際のプロパティ名を使用するという事実にありました。したがって、目的の動作を得るには、グリッドDisplayNameが実際のプロパティ名であると信じ込ませる必要があります。オブジェクト プロパティのさまざまな属性を検出するために使用しますPropertyGrid。を実際のプロパティ名として表示PropertyDescriptorsするカスタムPropertyDescriptorが必要なだけです。DisplayName次のコードを見てください。

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

以前のクラスは、既存のクラスをラップしPropertyDescriptor、'Name' プロパティの動作をオーバーライドするために使用されます。プロパティは、 (null または空でない場合) または実際のプロパティ名を返すNameようになりました。DisplayName他のすべての機能は、ラップされた に委譲されPropertyDescriptorます。

これで、提示されたプロパティ名を変更する方法ができました。必要なのPropertyGridは、 new を利用することだけですPropertyDescriptor。そのためには、カスタマイズされた が必要TypeDescriptorです。もう一度、次のコードを見てください。

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

このクラスは を継承しExpandableObjectConverterて、既存の動作を利用し、実装を最小限に抑えます。GetPropertiesメソッドをオーバーライドするだけです。このメソッドは、基本型に関連するものを取得するように要求し、PropertyDescriptorCollectionこのコレクションのすべての要素を .xml にラップしますDisplayNameEnforcingDescriptor。ラップされた要素を含むnewcollectionが返されます。

MyObjectクラスに 属性をDisplayNameEnforcingConverter付けると、並べ替えは常にプロパティに基づいて行われます。DisplayName

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

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

ここに画像の説明を入力

于 2013-07-12T22:33:51.147 に答える
0

PropertyGrid.PropertySortOrderのドキュメントには次のように記載されています。

カスタムの並べ替えを行うには、コンポーネントにICustomTypeDescriptorを実装して、必要な順序でプロパティを返します。

私はあなたのクラスを実装するように変更ICustomTypeDescriptorし、ICustomTypeDescriptorメソッドが呼び出され、属性によって順番にプロパティを返していましたがDisplayNamePropertyGrid.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

于 2013-07-11T03:06:59.513 に答える