带有自定义排序的WPF Propertygrid

时间:2013-04-25 12:03:17

标签: wpf propertygrid

我正在为我的WPF项目寻找一个PropertyGrid,它允许我自定义列出属性/类别的顺序。现在我正在使用Extended WPF Toolkit(社区版)PropertyGrid和CustomPropertyDescriptor s。我的研究表明,使用PropertyGrid进行自定义排序是不可能的。

是否有(最好是免费的)解决方案?

1 个答案:

答案 0 :(得分:1)

可以通过使用PropertyOrderAttribute属性修饰属性来实现Extended WPF Toolkit中属性的排序。

如果你不想通过在设计时用属性修饰它们来污染POCO,或者命令在某种程度上是动态的,那么可以通过创建类型转换器并覆盖GetProperties方法在运行时添加属性。 。例如,如果您希望维护通用IList类型的索引顺序:

using Xceed.Wpf.Toolkit.PropertyGrid.Attributes;
using System.ComponentModel;

 public class MyExpandableIListConverter<T> : ExpandableObjectConverter
{
    public override PropertyDescriptorCollection GetProperties(ITypeDescriptorContext context, object value, Attribute[] attributes)
    {
        if (value is IList<T>)
        {
            IList<T> list = value as IList<T>; 
            PropertyDescriptorCollection propDescriptions = new PropertyDescriptorCollection(null);
            IEnumerator enumerator = list.GetEnumerator();
            int counter = -1;
            while (enumerator.MoveNext())
            {
                counter++;
                propDescriptions.Add(new ListItemPropertyDescriptor<T>(list, counter));

            }
            return propDescriptions;
        }
        else
        {
            return base.GetProperties(context, value, attributes);
        }
    }        
}

ListItemPropertyDescriptor的定义如下:

using Xceed.Wpf.Toolkit.PropertyGrid.Attributes;
using System.ComponentModel;

public class ListItemPropertyDescriptor<T> : PropertyDescriptor
{
    private readonly IList<T> owner;
    private readonly int index;

    public ListItemPropertyDescriptor(IList<T> owner, int index) : base("["+ index+"]", null)
    {
        this.owner = owner;
        this.index = index;

    }

    public override AttributeCollection Attributes
    {
        get
        {
            var attributes = TypeDescriptor.GetAttributes(GetValue(null), false);
            //If the Xceed expandable object attribute is not applied then apply it
            if (!attributes.OfType<ExpandableObjectAttribute>().Any())
            {
                attributes = AddAttribute(new ExpandableObjectAttribute(), attributes);
            }

            //set the xceed order attribute
            attributes = AddAttribute(new PropertyOrderAttribute(index), attributes);

            return attributes;
        }
    }
    private AttributeCollection AddAttribute(Attribute newAttribute, AttributeCollection oldAttributes)
    {
        Attribute[] newAttributes = new Attribute[oldAttributes.Count + 1];
        oldAttributes.CopyTo(newAttributes, 1);
        newAttributes[0] = newAttribute;

        return new AttributeCollection(newAttributes);
    }

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

    public override object GetValue(object component)
    {
        return Value;
    }

    private T Value
      => owner[index];

    public override void ResetValue(object component)
    {
        throw new NotImplementedException();
    }

    public override void SetValue(object component, object value)
    {
        owner[index] = (T)value;
    }

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

    public override Type ComponentType
      => owner.GetType();

    public override bool IsReadOnly
      => false;

    public override Type PropertyType
      => Value?.GetType();

}

此代码的部分内容是根据following SO answer

改编的