Как изменить DisplayNameAttribute на времени выполнения для использования в Сетке Свойства C#

Я задаюсь вопросом, как изменить DisplayNameAttribute на времени выполнения, я хочу, чтобы displayName были Ноги вместо Метров в моей сетке свойства, когда я делаю некоторые преобразования, который возможен?

[DisplayName("Meters")]
public double Distance
  {
     get{return distance;}
  }
5
задан DogDog 10 March 2010 в 21:47
поделиться

4 ответа

Есть несколько способов сделать это. Самый простой - сделать что-то похожее на то, как это делают некоторые продукты i18n - создать подкласс атрибута и перехватить текст; но это работает только в том случае, если вы владеете типом, а из атрибута вы не можете получить доступ к контексту.

Следующее, на что стоит обратить внимание, будет TypeConverter , поскольку он обеспечивает доступ к представлению компонентной модели для свойств и проще, чем следующие два параметра ;-p Это будет работать с ] PropertyGrid , но не DataGridView и т. Д.

Следующим в списке идет ICustomTypeDescriptor - неинтересный интерфейс для реализации, но вы можете поменять местами свой собственный дескриптор свойства. . Для этого требуется, чтобы у вас был тип (чтобы обеспечить поддержку интерфейса).

Наконец, CustomTypeDescriptor похож на предыдущий, но работает даже с типами, которые вам не принадлежат, и позволяет получить доступ к измененным метаданным как для типа , так и для объекта и (все остальное поддерживает только объект ).

Что выбрать? Я подозреваю, что TypeConverter будет наиболее разумным; вам нужен объектный контекст (который атрибут подкласса не предоставляет), но вам не нужна дополнительная сложность.

Вот пример; обратите внимание, что в коде TypeConverter у нас есть доступ к объектному контексту. Если имя простое, достаточно поместить его в TypeConverter (при создании свойства).

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Windows.Forms;
class MyFunkyTypeConverter : ExpandableObjectConverter
{
    public override PropertyDescriptorCollection GetProperties(ITypeDescriptorContext context, object value, Attribute[] attributes)
    {
        PropertyDescriptorCollection props = base.GetProperties(context, value, attributes);
        List<PropertyDescriptor> list = new List<PropertyDescriptor>(props.Count);
        foreach (PropertyDescriptor prop in props)
        {
            switch (prop.Name)
            {
                case "Distance":
                    list.Add(new DisplayNamePropertyDescriptor(
                        prop, "your magic code here"));
                    break;
                default:
                    list.Add(prop);
                    break;
            }
        }
        return new PropertyDescriptorCollection(list.ToArray(), true);
    }
}
class DisplayNamePropertyDescriptor : PropertyDescriptor
{
    private readonly string displayName;
    private readonly PropertyDescriptor parent;
    public DisplayNamePropertyDescriptor(
        PropertyDescriptor parent, string displayName) : base(parent)
    {
        this.displayName = displayName;
        this.parent = parent;
    }
    public override string  DisplayName
    {get { return displayName; } }

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

    public override void SetValue(object component, object value) {
        parent.SetValue(component, value);
    }
    public override object GetValue(object component)
    {
        return parent.GetValue(component);
    }
    public override void ResetValue(object component)
    {
        parent.ResetValue(component);
    }
    public override bool CanResetValue(object component)
    {
        return parent.CanResetValue(component);
    }
    public override bool IsReadOnly
    {
        get { return parent.IsReadOnly; }
    }
    public override void AddValueChanged(object component, EventHandler handler)
    {
        parent.AddValueChanged(component, handler);
    }
    public override void RemoveValueChanged(object component, EventHandler handler)
    {
        parent.RemoveValueChanged(component, handler);
    }
    public override bool SupportsChangeEvents
    {
        get { return parent.SupportsChangeEvents; }
    }
    public override Type PropertyType
    {
        get { return parent.PropertyType; }
    }
    public override TypeConverter Converter
    {
        get { return parent.Converter; }
    }
    public override Type ComponentType
    {
        get { return parent.ComponentType; }
    }
    public override string Description
    {
        get { return parent.Description; }
    }
    public override PropertyDescriptorCollection GetChildProperties(object instance, Attribute[] filter)
    {
        return parent.GetChildProperties(instance, filter);
    }
    public override string Name
    {
        get { return parent.Name; }
    }

}

[TypeConverter(typeof(MyFunkyTypeConverter))]
class MyFunkyType
{
    public double Distance {get;set;}

    public double AnotherProperty { get; set; }
}
static class Program
{
    [STAThread]
    static void Main()
    {
        Application.EnableVisualStyles();
        Application.Run(new Form { Controls = {
            new PropertyGrid { Dock = DockStyle.Fill,
                SelectedObject = new MyFunkyType {
                    Distance = 123.45
                }}
        }});
    }
}
12
ответ дан 13 December 2019 в 05:33
поделиться

Я не знаю, сработает ли это, но ваше DisplayName является атрибутом. Каждый класс и члены каждого класса могут иметь набор атрибутов.Тем не менее, создается ощущение, что PropertyInfo предоставит вам доступ к этому атрибуту. Теперь, если вы пойдете по этому пути и встретите PropertyInfo.GetCustomAttributes () или что-то в этом роде, и вы получите значение своего атрибута, вы говорите, что он доступен только для чтения, как вы сказали Нику?

{{1} }
0
ответ дан 13 December 2019 в 05:33
поделиться

Атрибуты компилируются как часть типа, поэтому их нельзя изменить во время выполнения.

Альтернативным решением может быть определение внутренней единицы измерения, в которой вы всегда храните все значения. Метры - хороший кандидат. Затем создайте службы "транслятора", которые будут находиться между вашим потребительским классом и исходным классом и отвечать за преобразование всех значений в другой формат.

0
ответ дан 13 December 2019 в 05:33
поделиться

Устанавливать единицу измерения в отображаемом имени немного странно, но если это действительно то, что вы хотите сделать, то единственное решение - опубликовать ваши свойства с настраиваемыми дескрипторами PropertyDescriptors (благодаря TypeConverter или настраиваемым дескриптором типа) и переопределить свойство DisplayName.

Здесь тоже ответили: Изменить атрибут DisplayName для свойства

0
ответ дан 13 December 2019 в 05:33
поделиться
Другие вопросы по тегам:

Похожие вопросы: