Может ли PropertyGrid редактировать старый список пар ключ-значение? - PullRequest
5 голосов
/ 08 сентября 2010

Все примеры PropertyGrid, которые я видел, позволяют пользователю редактировать один объект, который PropertyGrid сканирует по отражению.Я хотел бы, чтобы пользователь мог редактировать, например, INI-файл или обычный словарь, по одной строке на пару ключ-значение.Возможно ли это?

Ответы [ 3 ]

5 голосов
/ 08 сентября 2010

Да. Несколько лет назад я написал некоторый код для отображения IDictionary в PropertyGrid.

3 голосов
/ 08 сентября 2010

Вот полный пример, полученный из кода, на который ссылается Роджер. Я обновил его так, чтобы

  • Используется 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 голосов
/ 08 сентября 2010

PropertyGrid позволит редактировать любое свойство, для которого получены и установлены средства доступа, или к нему прикреплен соответствующий редактор, или тип, который он предоставляет, описывающий, как преобразовать или даже отредактировать это значение.

ПоэтомуЕсли вы предоставляете свойство, например, Stream INI-файла, и прикрепляете пользовательский TypeConverter, который расширяет его до пар имя / значение в нем, вы действительно можете редактироватьINI-файл с PropertyGrid.

Полезные ссылки:

Преобразователи типов

Преобразователь типа присоединяется к типу с помощью объявления TypeConverterAttribute.Преобразователи типов позволяют вам предоставлять правила о том, как преобразовывать ваш тип в другие типы и из них.Предусмотрен ряд переопределений для настройки ваших преобразований, начиная с Convert.

Через различные вызовы GetPropertiesxxxx преобразователи типов также позволяют вам указать, какие свойства вашего типа можно редактировать и как онипоявляются (например, их имена).Это позволяет расширять значения (например, редактировать тип Point) и отображать или скрывать свойства в зависимости от состояния значения (например, ваш INI-файл будет использовать это для отображения или скрытия подготовленных свойств на основе содержимого).файла).

Преобразователи типов также позволяют указать список значений, которые ваш тип может отображать в раскрывающемся списке при редактировании.Это обеспечивается набором переопределений GetStandardValuesXxx и может быть полезным, если вы не хотите создавать пользовательский редактор, но у вас есть фиксированный список допустимых значений.

Editors

Editorsпозволяют точно настроить время проектирования при редактировании экземпляра типа.Они могут быть прикреплены к свойству или типу и указывают PropertyGrid, какой редактор использовать при редактировании значения.Это позволяет вам показать диалог или свой собственный выпадающий список с некоторым пользовательским интерфейсом (например, слайдером).

...