Главная » C#, Компоненты » Дескрипторы свойств

0

И свойство, и событие являются частями компонента, каждая из которых описывается с помощью класса, называемого дескриптором (descriptor). Базовым классом дескриптора является класс MemberDescriptor. Два наследника этого класса являются дескриптором свойств (класс PropertyDescriptor) И дескриптором событий (EventDescriptor).

Класс PropertyDescriptor является абстрактным и имеет следующие абстрактные свойства и методы:

?        свойство туре componentType { get; } возвращает тип компонента;

П свойство bool isReadOnly { get; } возвращает true, если свойство доступно только для чтения;

?        свойство туре PropertyType { get; } возвращает тип свойства;

?        метод bool CanResetValue (object component); возвращает true, если доступен метод сброса значения свойства в значение по умолчанию (меню Reset);

?        метод object Getvalue(object component); возвращает значение свойства для данного компонента;

? метод void Resetvaiue (object component),- сбрасывает значение свойства в значение по умолчанию;

О метод void Setvaiue (object component, object value); устанавливает значение свойства;

О метод bool ShouldSerializeValue (object component); возвращает true, если значение свойства должно сериализоваться (см. главу 10).

Метод Setvaiue о очень важен в режиме разработки. Дело в том, что среда Visual Studio и, в частности, дизайнер формы не могут отследить все присваивания значения свойств всех компонентов. Например, при изменении одного свойства в коде компонента меняется значение другого. Если присвоение делать напрямую, то дизайнер формы не имеет возможности узнать об этом, т. к. будет выполнен только код аксессора set этого свойства. Правильный путь — использовать метод setvaiue () дескриптора нужного свойства. Именно такое присвоение позволит среде разработки узнать об изменении свойства. Получить дескриптор можно с помощью метода:

private PropertyDescriptor GetPropertyByName(

Component component, string propertyName)

{

PropertyDescriptor prop =

TypeDescriptor.GetProperties(component)[propertyName]; if (prop == null) I

throw new ArgumentException("Свойство не существует", propName);

{

return prop;

}

Вызов метода будет выглядеть примерно так:

GetPropertyByName("StartColor").SetValue(glabel, value);

Теперь, когда все нужные службы будут оповещены об изменении значения свойства, присвоение значения свойства будет корректным, например, будет работать команда меню Undo (Отмена). Разумеется, в режиме выполнения такие сложности не нужны и вполне достаточно простого присвоения значения свойства.

Класс EventDescriptor является абстрактным и имеет следующие абстрактные свойства и методы:

С! свойство туре ComponentType { get; } возвращает тип компонента; С! свойство туре EventType { get; ( возвращает тип события;

?        свойство booi isMuiticast { get; } возвращает true, если делегат- обработчик представляет собой цепочку делегатов;

?        метод void AddEventHandler(object component, Delegate value); добавляет обработчик к событию;

О метод void RemoveEventHandler(object component, Delegate value); удаляет обработчик события.

Списки событий и свойств описываются с помощью классов

PropertyDescriptorCollection И EventDescriptorCollection.Для ИХ получения используются статические методы GetProperties () и GetEventso класса TypeDescriptor (ЛИСТИНГ 4.2).

Заметьте, что все три класса, которые я описал выше, являются абстрактными. Использовать их напрямую (например, для создания нового свойства) не получится. Вариантов два. Во-первых, в классе TypeConverter (см. главу 8) содержится внутренний класс SimplePropertyDescriptor, который позволяет частично решить эту проблему. Я буду рассказывать о нем в разд. 8.6. Во- вторых, можно попробовать реализовать собственный класс, являющийся наследником соответствующего базового класса. Например, в листинге 4.3 содержится пример дескриптора для SQL-типов свойств. Самое сложное здесь — методы Getvaiue () и Setvaiue (). Вначале нужно обработать значение DBNuii, а затем с помощью методов отражения либо получить, либо установить новое значение свойства. Диалогично можно реализовать и другие варианты дескрипторов.

Листинг 4.2, Получение списка свойств и событий компонента

using System;

using System.Collections.Generic;

using System.ComponentModel;

using System.Data;

using System.Drawing;

using System.Text;

using System.Windows.Forms;

namespace Test {

public partial class Forml : Form {

public Forml() {

InitializeComponent();

private void Forml_Load(object sender, EventArgs e) {

11 Получаем коллекцию дескрипторов свойств PropertyDescriptorCollection pdc =

TypeDescriptor.GetProperties(this);

if (pdc != null && pdc.Count > 0) {

Info.Items.Add("Список свойств:"); // Вьшодим список свойств

foreach (PropertyDescriptor pdi in pdc) {

Info.Items.Add(string.Format("{0}", pdi.Name));

}

}

/ / Получаем коллекцию дескрипторов событий

EventDescriptorCollection edc = TypeDescriptor.GetEvents(this);

if (edc != null && edc.Count > 0) {

Info.Items.Add("Список событий:"); // Выводим список событий

foreach (EventDescriptor edi in edc) {

Info.Items.Add(string.Format("{0}", edi.Name));

}

}

}

}

}

Листинг 4.3. Пример реализации дескриптора свойств

using System;

using System. Data. SqlTypes; using System. ComponentModel; using System.Collections; using System.Reflection; using System. Diagnostics;

public class SqlPropertyDescriptor : PropertyDescriptor

}

private Type SqlType; private Type BaseType;

/// Конструктор

public static SqlPropertyDescriptor GetProperty(

string name, Type sqlType)

{

// Чтобы вызвать конструктор базового класса, нужен // список атрибутов свойства

Type baseType = sqlType.GetProperty("Value").PropertyType; ArrayList attribs =

new ArrayList(TypeDescriptor.GetAttributes(baseType)); Attribute[] attrs =

(Attribute[])attribs.ToArray(typeof(Attribute)); // Вызываем конструктор базового класса

return new SqlPropertyDescriptor(name, attrs, sqlType, baseType);

}

// Эти конструкторы нам не нужны protected SqlPropertyDescriptor(

MemberDescriptor descr) : base(descr) { ) protected SqlPropertyDescriptor(MemberDescriptor descr,

Attribute[] attrs) : base(descr, attrs) { ) protected SqlPropertyDescriptor(string name,

Attribute[] attrs) : base(name, attrs) { )

// Мы используем этот конструктор protected SqlPropertyDescriptor(string name,

Attribute[] attrs, Type sqlType, Type baseType) : base(name, attrs)

SqlType = sqlType; BaseType = baseType;

}

public override bool CanResetValue(object component) return false;

}

public override void ResetValue(object component) {

throw new NotSupportedException();

public override bool ShouldSerializeValuo{object component) i

return fa]se;

}

public override Type ComponentType

{

get { return BaseType; }

public override bool IsReadOnly get ( return false; }

1

public override Type PropertyType

f

get { return BaseType; }

}

public override void SetValue(object component, object value} f

try

// Получаем информацию о свойстве

Propertylnfo pi = component.GetТуре{).GetPropertv(th:s.Name); Object o;

if (value — DBNull.Value) {

// Если это DBNull, возвращаем статическое свойство Null о = component. GetTypeO . GetField ("Null",

BindingFlags.Static I BindingFlags.PubLi с | BindingFlags.GctField).GetValue(component);

}

else

{

// Создаем экземпляр значения свойства о = pi.PropertyType.GetConstructor(

new ТуреП i BaseType }). Invoke (new Obiectf] f value });

}

// Устанавливаем значение свойства pi. SetValue(component, o, null);

catch (Exception ex) (

// Какая-нибудь обработка исключения Debug.WriteLine(ex) ;

}

}

public override object GetVdlue(object component) {

try

{

object Property = component.GetType().GetProperty(

this.Name).Getvalue(component, null);

// Если это Null, то возвращаем DBNull

if ((bool)Property.GetType0 .GetProperty("IsNull").

Getvalue(Property, null)) return DBNull.value;

// Возвращаем значение свойства

object Value = Property.GetType0 .GetProperty("Value"). Getvalue(Property, null);

return Value;

}

catch (Exception ex) {

// Какая-нибудь обработка исключения Debug.WriteLine(ex) ;

}

return null;

}

}

Литература:

Агуров П. В. C#. Разработка компонентов в MS Visual Studio 2005/2008. – СПб.: БХВ-Петербург, 2008. — 480 е.: ил.

По теме:

  • Комментарии