Объединение нескольких атрибутов в один атрибут
на элементе управления я использую несколько свойств атрибута:
[Browsable(false)]
[Bindable(false)]
[EditorBrowsable(EditorBrowsableState.Never)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
[Obsolete("", true)]
public new Boolean AllowDrop;
Я использую эти свойства во многих других свойствах элемента управления.
мне интересно, есть ли способ уменьшить количество кода для записи каждый раз.
было бы неплохо, если бы я мог объединить несколько атрибутов такой:
[Hidden(true)]
public new Boolean AllowDrop;
здесь Hidden
свойство будет включать все атрибуты выше. Так что есть только 1 строка код.
может быть, есть также способ объединить атрибуты в макрос или что-то еще?
Я знаю, что есть другие способы скрыть свойства, но я выбрал способ использования атрибутов.
спасибо
1 ответов
объединение атрибутов может быть значимым для контекста, который использует и интерпретирует атрибуты. Например, для контекстов, использующих механизмы описания типов .Net, можно настроить описание типа, которое .Net возвращает потребителям.
можно предоставить пользовательские метаданные для типов с помощью стандартного механизма .Net для этой цели, зарегистрировав пользовательский дескриптор типа для вашего объекта.
идея будет работать таким образом, вы создаете настраиваемый дескриптор типа для вашего типа. В пользовательском дескрипторе типа возвращаются пользовательские дескрипторы свойств для свойств типа, а в дескрипторе свойства возвращается пользовательский набор атрибутов для свойства.
подход требует больше кода, но это действительно интересно и имеет некоторые хорошие идеи о том, чтобы предоставить пользовательские метаданные для вашего типа:
Интерфейс IMetedataAttribute
использование обеспечивает стандартный способ создания MetaDataAttribues. Каждый attriute, который реализует этот интерфейс, будет использоваться как метаданные, а не атрибут, тот, который он возвращает в Process
метод будет использоваться:
public interface IMetadatAttribute
{
Attribute[] Process();
}
Образец MetadataAttribue
это пример атрибута метаданных, который возвращает некоторый атрибут при обработке атрибута:
public class MySampleMetadataAttribue : Attribute, IMetadatAttribute
{
public Attribute[] Process()
{
var attributes = new Attribute[]{
new BrowsableAttribute(false),
new EditorBrowsableAttribute(EditorBrowsableState.Never),
new BindableAttribute(false),
new DesignerSerializationVisibilityAttribute(
DesignerSerializationVisibility.Hidden),
new ObsoleteAttribute("", true)
};
return attributes;
}
}
Дескриптор Свойства
этот класс будет используется дескриптором пользовательского типа для предоставления настраиваемого списка атрибутов свойства:
public class MyPropertyDescriptor : PropertyDescriptor
{
PropertyDescriptor original;
public MyPropertyDescriptor(PropertyDescriptor originalProperty)
: base(originalProperty) { original = originalProperty;}
public override AttributeCollection Attributes
{
get
{
var attributes = base.Attributes.Cast<Attribute>();
var result = new List<Attribute>();
foreach (var item in attributes)
{
if(item is IMetadatAttribute)
{
var attrs = ((IMetadatAttribute)item).Process();
if(attrs !=null )
{
foreach (var a in attrs)
result.Add(a);
}
}
else
result.Add(item);
}
return new AttributeCollection(result.ToArray());
}
}
// Implement other properties and methods simply using return original
// The implementation is trivial like this one:
// public override Type ComponentType
// {
// get { return original.ComponentType; }
// }
}
Дескриптор Типа
это дескриптор типа, который предоставляет пользовательское описание для вашего типа. В этом примере он использует пользовательские дескрипторы propertuy для предоставления пользовательских атрибутов, заданных для свойств вашего класса:
public class MyTypeDescriptor : CustomTypeDescriptor
{
ICustomTypeDescriptor original;
public MyTypeDescriptor(ICustomTypeDescriptor originalDescriptor)
: base(originalDescriptor)
{
original = originalDescriptor;
}
public override PropertyDescriptorCollection GetProperties()
{
return this.GetProperties(new Attribute[] { });
}
public override PropertyDescriptorCollection GetProperties(Attribute[] attributes)
{
var properties = base.GetProperties(attributes).Cast<PropertyDescriptor>()
.Select(p => new MyPropertyDescriptor(p))
.ToArray();
return new PropertyDescriptorCollection(properties);
}
}
Поставщик Typedescriptor
этот класс будет использоваться в атрибут над типом, чтобы ввести пользовательский дескриптор типа, который мы создали в качестве движка метаданных для типа:
public class MyTypeDescriptionProvider : TypeDescriptionProvider
{
public MyTypeDescriptionProvider()
: base(TypeDescriptor.GetProvider(typeof(object))) { }
public override ICustomTypeDescriptor GetTypeDescriptor(Type objectType,
object instance)
{
ICustomTypeDescriptor baseDescriptor = base.GetTypeDescriptor(objectType, instance);
return new MyTypeDescriptor(baseDescriptor);
}
}
Образец Класс
вот мой образец класса, который его Name
свойство оформляется с помощью MySampleMetadataAttribute
и сам класс зарегистрирован для использования нашего поставщика пользовательских дескрипторов типов:
[TypeDescriptionProvider(typeof(MyTypeDescriptionProvider))]
public class MySampleClass
{
public int Id { get; set; }
[MySampleMetadataAttribue]
[DisplayName("My Name")]
public string Name { get; set; }
}
чтобы увидеть результат, достаточно создать экземпляр класса и увидеть результат в PropertyGrid
:
var o = new MySampleClass();
this.propertyGrid1.SelectedObject = o;
некоторые заметки об ответе
- вероятно, это не так просто, как вы ожидали для такой задачи. Но это работает.
- это длинный ответ, но содержит полный рабочий пример того, как вы можете применять дескрипторы типов к своим типам для предоставления пользовательских метаданных.
- подход не будет работать для двигателей, которые используют отражение вместо описания типа. Но это полностью работает, например
PropertyGrid
управление, которое работает с описанием типа.