代码之家  ›  专栏  ›  技术社区  ›  Qwertie

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

  •  5
  • Qwertie  · 技术社区  · 14 年前

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

    3 回复  |  直到 9 年前
        1
  •  5
  •   Roger Lipscombe    9 年前

    对。几年前,我写道 some code 显示一个 IDictionary 在一个 PropertyGrid .

        2
  •  3
  •   Qwertie    14 年前

    下面是一个完整的例子,源于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;
            }
        }
    }
    
        3
  •  2
  •   Jeff Yates    14 年前

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

    因此,如果公开一个属性,例如, Stream 并附加自定义 TypeConverter 如果将其扩展到其中的名称/值对,则确实可以使用 属性表格 .

    有用链接:

    型变换器

    类型转换器使用 类型转换器属性 宣言。类型转换器允许您提供有关如何将类型转换为其他类型和从其他类型转换为其他类型的规则。提供了一系列覆盖来定制您的转换,所有这些都从 Convert .

    通过各种 GetPropertiesxxxx 调用时,类型转换器还允许您指定类型具有哪些可编辑的属性以及它们的显示方式(例如,它们的名称)。这使得可以展开值(如编辑 Point 键入)并根据值的状态显示或隐藏属性(例如,您的ini文件将使用此选项显示或隐藏基于文件内容的组合属性)。

    类型转换器还允许您指定类型在编辑时可以作为下拉列表显示的值列表。这是由 GetStandardValuesXxx 如果不想创建自定义编辑器,但有固定的允许值列表,则可以使用一组替代。

    编辑

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