Я задаюсь вопросом, как изменить DisplayNameAttribute на времени выполнения, я хочу, чтобы displayName были Ноги вместо Метров в моей сетке свойства, когда я делаю некоторые преобразования, который возможен?
[DisplayName("Meters")]
public double Distance
{
get{return distance;}
}
Есть несколько способов сделать это. Самый простой - сделать что-то похожее на то, как это делают некоторые продукты 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
}}
}});
}
}
Я не знаю, сработает ли это, но ваше DisplayName является атрибутом. Каждый класс и члены каждого класса могут иметь набор атрибутов.Тем не менее, создается ощущение, что PropertyInfo предоставит вам доступ к этому атрибуту. Теперь, если вы пойдете по этому пути и встретите PropertyInfo.GetCustomAttributes () или что-то в этом роде, и вы получите значение своего атрибута, вы говорите, что он доступен только для чтения, как вы сказали Нику?
{{1} }Атрибуты компилируются как часть типа, поэтому их нельзя изменить во время выполнения.
Альтернативным решением может быть определение внутренней единицы измерения, в которой вы всегда храните все значения. Метры - хороший кандидат. Затем создайте службы "транслятора", которые будут находиться между вашим потребительским классом и исходным классом и отвечать за преобразование всех значений в другой формат.
Устанавливать единицу измерения в отображаемом имени немного странно, но если это действительно то, что вы хотите сделать, то единственное решение - опубликовать ваши свойства с настраиваемыми дескрипторами PropertyDescriptors (благодаря TypeConverter или настраиваемым дескриптором типа) и переопределить свойство DisplayName.
Здесь тоже ответили: Изменить атрибут DisplayName для свойства