如何在winforms中创建Readonly可扩展属性PropertyGrid

时间:2016-04-07 04:31:29

标签: c# winforms propertygrid

我正在开发一个winforms应用程序,它以一种相当复杂的方式使用标准的winforms属性网格。

我为类提供了自定义类型描述符和类型转换器,并且还指定了某些属性是否只读,并且在属性网格中不可编辑。

我在确定如何拥有一个也是只读的可扩展类型时遇到问题 - 在文档中似乎覆盖public bool IsReadOnly是可行的方法但是只要我在类型转换器中指定有子节点属性它停止工作。

我设法将我的代码提炼为一个小例子:

这是自定义对象:

public sealed class TestNode : ICustomTypeDescriptor
{
    private readonly bool _isEditable;
    private readonly List<TestNode> _childNodes = new List<TestNode>();

    public TestNode(string name, bool isEditable = true)
    {
        _isEditable = isEditable;
        Name = name;
    }

    public string Name { get; private set; }

    public bool IsEditable
    {
        get { return _isEditable; }
    }

    public List<TestNode> ChildNodes
    {
        get { return _childNodes; }
    }

    public void AddChild(TestNode testNode)
    {
        ChildNodes.Add(testNode);
    }


    #region ICustomTypeDescriptor

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

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

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

    public PropertyDescriptorCollection GetProperties()
    {
        return GetProperties(new Attribute[0]);
    }

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

    public PropertyDescriptorCollection GetProperties(Attribute[] attributes)
    {
        return new PropertyDescriptorCollection(new PropertyDescriptor[]{new TestNodeDescriptor(this)}, true);
    }

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

    #endregion
}

其中有一个这样的描述符,我可以指定它是否在propertyGrid中显示为readonly:

public class TestNodeDescriptor : PropertyDescriptor
{
    private readonly TestNode _testNode;

    public TestNodeDescriptor(TestNode testNode) : base("Test", null)
    {
        _testNode = testNode;
    }

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

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

    public override void ResetValue(object component)
    {
    }

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

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

    public override Type ComponentType
    {
        get { return null; }
    }

    public override bool IsReadOnly
    {
        get { return !_testNode.IsEditable; }
    }

    public override Type PropertyType
    {
        get { return typeof(TestNode); }
    }

    public override TypeConverter Converter
    {
        get
        {
            return new TestTypeConverter(_testNode);
        }
    }
}

最后是类型转换器,我在其中指定转换为字符串以进行显示,并使用所需的可扩展类型转换器来显示子属性:

public class TestTypeConverter : ExpandableObjectConverter
{
    private readonly TestNode _testNode;

    public TestTypeConverter(TestNode testNode)
    {
        _testNode = testNode;
    }

    public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
    {
        return destinationType == typeof(string);
    }

    public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
    {
        return _testNode.Name;
    }

    public override PropertyDescriptorCollection GetProperties(ITypeDescriptorContext context, object value, Attribute[] attributes)
    {
        var descriptors = _testNode.ChildNodes.Select(c => (PropertyDescriptor) (new TestNodeDescriptor(c))).ToArray();
        return new PropertyDescriptorCollection(descriptors);
    }

    public override bool GetPropertiesSupported(ITypeDescriptorContext context)
    {
        return _testNode.ChildNodes.Any();
    }
}

奇怪的是,如果类型转换器public override bool GetPropertiesSupported(ITypeDescriptorContext context) 中的方法返回true,则子项将按预期显示,但不是readonly。

例如,使用此测试代码:

public partial class Form1 : Form
{
    readonly TestNode _parentNode = new TestNode("Parent");
    public Form1()
    {
        InitializeComponent();

        var child1 = new TestNode("Child1", false);

        var child2 = new TestNode("Child2", false);
        child2.AddChild(new TestNode("Grandchild", false));

        _parentNode.AddChild(child2);
        _parentNode.AddChild(child1);



        propertyGrid1.SelectedObject = _parentNode;
    }
}

我会得到一个像这样的对话节目:

enter image description here

我期待所有子节点都是只读的。有没有人有这样的东西能成功使用PropertyGrid?

这是一次非常令人沮丧的经历,我们将非常感谢任何提示。

0 个答案:

没有答案