PropertyGrid可以编辑任何旧的键值对列表吗?

时间:2010-09-08 16:02:14

标签: .net winforms propertygrid

我见过的所有PropertyGrid示例都允许用户编辑单个对象,PropertyGrid通过反射进行扫描。我希望用户能够编辑例如ini文件或普通旧词典,每个键值对一行。这可能吗?

3 个答案:

答案 0 :(得分:5)

是。几年前,我写了some code以在IDictionary中显示PropertyGrid

答案 1 :(得分:3)

这是一个从Roger链接到的代码派生的完整示例。我更新了它以便

  • 它使用Dictionary<GridProperty,object>代替IDictionary
  • 每个GridProperty指定名称,类别,描述等。

(注意,这篇文章已经改变了原来的设计。)谢谢罗杰!

public partial class PropertyEditor : Form
{
    public PropertyEditor()
    {
        InitializeComponent();

        var dict = new Dictionary<GridProperty, object>();
        dict["Food"] = "Poutine";
        dict["Ball"] = "Football";
        dict[new GridProperty("1. Greeting", "Words", "The first word to say")] = "Hello";
        dict[new GridProperty("2. Subject", "Words", "The second word to say")] = "Dogs";
        dict[new GridProperty("3. Verb", "Words", "The third word to say")] = "Like";
        dict[new GridProperty("4. Object", "Words", "The fourth word to say")] = "Burritos";
        dict[new GridProperty("Integer", "Types", "")] = 42;
        dict[new GridProperty("Double", "Types", "")] = 42.5;
        dict[new GridProperty("Color", "Types", "")] = Color.ForestGreen;

        propertyGrid1.SelectedObject = new DictionaryPropertyGridAdapter(dict, "Stuff");
    }
}

/// <summary>
/// Holds information about a property in a Dictionary-based PropertyGrid
/// </summary>
public class GridProperty
{
    public GridProperty(string name)
        { Name = name; }
    public GridProperty(string name, string category)
        { Name = name; Category = category; }
    public GridProperty(string name, string category, string description)
        { Name = name; Category = category; Description = description; }

    public string Name { get; private set; }
    public string Category { get; private set; }
    public string Description { get; set; }
    public bool IsReadOnly { get; set; }
    public object DefaultValue { get; set; } // shown if value is null

    public static implicit operator GridProperty(string name) { return new GridProperty(name); }
}

/// <summary>An object that wraps a dictionary so that it can be used as the
/// SelectedObject property of a standard PropertyGrid control.</summary>
/// <example>
/// propertyGrid.SelectedObject = new DictionaryPropertyGridAdapter(dict, "");
/// </example>
public class DictionaryPropertyGridAdapter : ICustomTypeDescriptor
{
    internal IDictionary<GridProperty, object> _dictionary;
    internal string _defaultCategory;

    public DictionaryPropertyGridAdapter(Dictionary<GridProperty, object> dict, string defaultCategory)
    {
        _dictionary = dict;
        _defaultCategory = defaultCategory;
    }

    public PropertyDescriptorCollection GetProperties(Attribute[] attributes)
    {
        var props = new PropertyDescriptor[_dictionary.Count];
        int i = 0;
        foreach (var prop in _dictionary)
            props[i++] = new GridPropertyDescriptor(prop.Key, this);
        return new PropertyDescriptorCollection(props);
    }

    #region Boilerplate

    #region Never called
    public string GetComponentName()
    {
        return TypeDescriptor.GetComponentName(this, true);
    }
    public EventDescriptor GetDefaultEvent()
    {
        return TypeDescriptor.GetDefaultEvent(this, true);
    }
    EventDescriptorCollection System.ComponentModel.ICustomTypeDescriptor.GetEvents()
    {
        return TypeDescriptor.GetEvents(this, true);
    }
    PropertyDescriptorCollection System.ComponentModel.ICustomTypeDescriptor.GetProperties()
    {
        return GetProperties(null);
    }
    #endregion

    public string GetClassName()
    {
        return TypeDescriptor.GetClassName(this, true);
    }
    public EventDescriptorCollection GetEvents(Attribute[] attributes)
    {
        return TypeDescriptor.GetEvents(this, attributes, true);
    }
    public TypeConverter GetConverter()
    {
        return TypeDescriptor.GetConverter(this, true);
    }
    public object GetPropertyOwner(PropertyDescriptor pd)
    {
        return _dictionary;
    }
    public AttributeCollection GetAttributes()
    {
        return TypeDescriptor.GetAttributes(this, true);
    }
    public object GetEditor(Type editorBaseType)
    {
        return TypeDescriptor.GetEditor(this, editorBaseType, true);
    }
    public PropertyDescriptor GetDefaultProperty()
    {
        return null;
    }

    #endregion

    class GridPropertyDescriptor : PropertyDescriptor
    {
        GridProperty _prop;
        DictionaryPropertyGridAdapter _parent;

        internal GridPropertyDescriptor(GridProperty prop, DictionaryPropertyGridAdapter parent)
            : base(prop.Name, null)
        {
            _prop = prop;
            _parent = parent;
        }
        public override string Description
        {
            get { return _prop.Description; }
        }
        public override string Category
        {
            get { return _prop.Category ?? _parent._defaultCategory; }
        }
        public override Type PropertyType
        {
            get { return (_parent._dictionary[_prop] ?? _prop.DefaultValue ?? "").GetType(); }
        }
        public override void SetValue(object component, object value)
        {
            _parent._dictionary[_prop] = value;
        }
        public override object GetValue(object component)
        {
            return _parent._dictionary[_prop];
        }
        public override bool IsReadOnly
        {
            get { return _prop.IsReadOnly; }
        }
        public override Type ComponentType
        {
            get { return null; }
        }
        public override bool CanResetValue(object component)
        {
            return _prop.DefaultValue != null;
        }
        public override void ResetValue(object component)
        {
            SetValue(component, _prop.DefaultValue);
        }
        public override bool ShouldSerializeValue(object component)
        {
            return false;
        }
    }
}

答案 2 :(得分:2)

PropertyGrid将允许编辑任何具有get和set访问器的属性或附加到其上的适当编辑器或其提供的类型,描述如何转换甚至编辑该值。

因此,如果您公开一个属性,例如,一个INI文件的Stream并附加一个自定义TypeConverter,将其扩展为其中的名称/值对,您确实可以使用PropertyGrid编辑INI文件。

有用的链接:

类型转换器

使用TypeConverterAttribute声明将类型转换器附加到类型。类型转换器允许您提供有关如何将类型转换为其他类型和从其他类型转换类型的规则。我们提供了一系列覆盖来定制您的转化,所有这些都以Convert开头。

通过各种GetPropertiesxxxx调用,类型转换器还允许您指定您的类型可以编辑的属性以及它们的显示方式(例如,它们的名称)。这样可以扩展值(如编辑Point类型)并根据值的状态显示或隐藏属性(例如,您的INI文件将使用它来显示或隐藏基于的属性文件的内容)。

类型转换器还允许您在编辑时指定类型可以显示为下拉列表的值列表。这是由GetStandardValuesXxx覆盖集提供的,如果您不想创建自定义编辑器但是您有一个固定的允许值列表,则可能很有用。

编辑

编辑器允许您微调编辑类型实例的设计时体验。它们可以附加到属性或类型,并在编辑值时向PropertyGrid指示要使用的编辑器。这允许您使用一些自定义用户界面(例如,滑块)显示对话框或您自己的下拉列表。