带有自定义排序的WPF Propertygrid

带有自定义排序的WPF Propertygrid,wpf,propertygrid,Wpf,Propertygrid,我正在为我的WPF项目寻找一个PropertyGrid,它允许我自定义列出的属性/类别的顺序。现在我正在使用s(社区版)PropertyGrid和CustomPropertyDescriptors。我的研究表明,使用该属性网格进行自定义排序是不可能的 是否有(最好是免费的)解决方案?扩展WPF工具包中的属性排序可以通过使用PropertyOrderAttribute属性装饰属性来实现 如果您不想在设计时用属性装饰POCO,或者顺序在某种程度上是动态的,那么可以通过创建类型转换器并重写GetPro

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


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

扩展WPF工具包中的属性排序可以通过使用PropertyOrderAttribute属性装饰属性来实现

如果您不想在设计时用属性装饰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);
        }
    }        
}
使用Xceed.Wpf.Toolkit.PropertyGrid.Attributes;
使用系统组件模型;
公共类MyExpandableIListConverter:ExpandableObjectConverter
{
公共重写属性描述或集合GetProperties(ITypeDescriptorContext上下文、对象值、属性[]属性)
{
if(值为IList)
{
IList list=作为IList的值;
PropertyDescriptorCollection propDescriptions=新的PropertyDescriptorCollection(null);
IEnumerator枚举器=list.GetEnumerator();
int计数器=-1;
while(枚举数.MoveNext())
{
计数器++;
添加(新的ListItemPropertyDescriptor(列表,计数器));
}
返回描述;
}
其他的
{
返回base.GetProperties(上下文、值、属性);
}
}        
}
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();

}
使用Xceed.Wpf.Toolkit.PropertyGrid.Attributes;
使用系统组件模型;
公共类ListItemPropertyDescriptor:PropertyDescriptor
{
私有只读IList所有者;
私有只读int索引;
公共ListItemPropertyDescriptor(IList所有者,int索引):基(“[”+索引+“]),null)
{
this.owner=所有者;
这个指数=指数;
}
公共覆盖属性集合属性
{
得到
{
var attributes=TypeDescriptor.GetAttributes(GetValue(null),false);
//如果未应用Xceed可扩展对象属性,则应用它
如果(!attributes.OfType().Any())
{
attributes=AddAttribute(新的ExpandableObjectAttribute(),attributes);
}
//设置xceed order属性
属性=添加属性(新属性或属性(索引),属性);
返回属性;
}
}
私有属性集合AddAttribute(属性newAttribute、属性集合oldAttributes)
{
属性[]新属性=新属性[oldAttributes.Count+1];
CopyTo(newAttributes,1);
newAttributes[0]=newAttribute;
返回新属性集合(newAttributes);
}
公共覆盖布尔CanResetValue(对象组件)
{
返回false;
}
公共覆盖对象GetValue(对象组件)
{
返回值;
}
私人T值
=>所有者[索引];
公共替代无效重置值(对象组件)
{
抛出新的NotImplementedException();
}
公共覆盖无效设置值(对象组件、对象值)
{
所有者[索引]=(T)值;
}
公共重写bool ShouldSerializeValue(对象组件)
{
返回false;
}
公共重写类型ComponentType
=>owner.GetType();
公共覆盖布尔为只读
=>假;
公共覆盖类型PropertyType
=>值?.GetType();
}

此代码的部分内容改编自扩展WPF工具包中的属性排序,可以通过使用PropertyOrderAttribute属性装饰属性来实现

如果您不想在设计时用属性装饰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);
        }
    }        
}
使用Xceed.Wpf.Toolkit.PropertyGrid.Attributes;
使用系统组件模型;
公共类MyExpandableIListConverter:ExpandableObjectConverter
{
公共重写属性描述或集合GetProperties(ITypeDescriptorContext上下文、对象值、属性[]属性)
{
if(值为IList)
{
IList list=作为IList的值;
PropertyDescriptorCollection propDescriptions=新的PropertyDescriptorCollection(null);
IEnumerator枚举器=list.GetEnumerator();
int计数器=-1;
while(枚举数.MoveNext())
{
计数器++;
添加(新的ListItemPropertyDescriptor(列表,计数器));
}
返回描述;
}
其他的
{
返回base.GetProperties(上下文、值、属性);
}
}        
}
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();

}
使用Xceed.Wpf.Toolkit.PropertyGrid.Attributes;
使用系统组件模型;
公共类ListItemPropertyDescriptor:PropertyDescriptor
{
私有只读IList所有者;
私有只读int索引;
公共ListItemPropertyDescriptor(IList所有者,int索引):基(“[”+索引+“]),null)
{
this.owner=所有者;
这个指数=指数;
}
公共覆盖属性集合属性
{
得到
{
var attributes=TypeDescriptor.GetAttributes(GetValue(null),false);
//如果“Xceed可扩展对象”属性为“否”