Главная » C#, Компоненты » Редактирование флагов

0

В разд. 8.3 я показал, как использовать конвертер Enumconverter при редактировании перечисления. Теперь я хочу рассказать, как редактировать перечисление, если оно отмечено флагом Flags, т. е. возможно выбрать несколько значений перечисления. Разумеется, значения флагов должны иметь значения степеней двойки:

[Flags]

public enum Operation {

[Description("He выбрано")] None = 0,

[0езсг1р^оп{"Сложение") ] Add = 1,

[Description("Вычитание")J Sub = 2,

[Description("Умножение")J Mul = 4,

[Description("Деление")] Dev – 8

}

Основная идея — сделать конвертер, который будет создавать набор виртуальных свойств, в соответствии со значениями перечисления. Каждое из таких свойств должно иметь тип bool. Если оно имеет значение true, значит, соответствующий флаг выставлен. Значение None (числовое значение о) говорит о том, что ни один из флагов не выставлен, поэтому в список виртуальных свойств оно попадать не должно.

Как мы уже обсуждали, класс PropertyDescriptor является абстрактным, поэтому нам потребуется свой класс дескриптора. Методы Getvaiue () и setvalue () должны отражать работу с битовыми флагами. Алгоритм создания списка свойств выглядит следующим образом:

1.          Получаем все значения перечисления.

2.          Просматриваем все значения.

3.          Если это значение о (т. е. None), мы его пропускаем, т. к. оно не нужно в списке свойств.

4.          Пытаемся получить значение атрибута Description. Если атрибут задан, мы будем использовать это значение как имя свойства, а если не задан, то будем использовать само значение.

5.       Создаем новый дескриптор и добавляем его в выходную коллекцию.

6,     На основе полученной коллекции создаем коллекцию PropertyDescrip- torCollection.

Полный код конвертера и дескриптора (он является внутренним классом конвертера) представлен в листинге 8.12. Как это выглядит в редакторе свойств, показано на рис. 8.8.

Работа с флагами заключается в трех операциях (переменная vai представляет текущее значение, а переменная value — значение флага):

?   (vai & value) > о—проверка, что флаг value установлен в значении vai;

?   vai i value — установка флага;

?   vai & -value — сброс флага.

В остальном код ничего нового не содержит. Все эти операции мы уже разбирали.

Листинг 8 12 Конвертер флагов

using System;

using System.Collections.Generic; using System.Text; using System.ComponentModel; using System.Reflection;

namespace MyControl

}

public class FlagsEnumConverter ; TypeConverter

{

// Это составное свойство

public override bool GetPropertiesSupported(

ITypeDescriptorContext context)

{

return true;

}

// Возвращаем коллекцию дескрипторов свойств public override PropertyDescriptorCollection GetProperties ( ITypeDescriptorContext context, object value, Attribute[] attributes)

{

// Получаем все значения перечисления Array values = Enum.GetValues{

context.PropertyDescriptor.PropertyType);

// Тип перечисления

Type propType = context.PropertyDescriptor.PropertyType;

11 Выходная коллекция дескрипторов List<PropertyDescriptor> outputCollection =

new List<PropertyDescriptor>();

11 Переписываем значения как свойства

for (int i = 0; i < values.Length; i++)

{

object propValue = values.GetValue(i);

// Значение 0 (none) пропускаем if (Convert.ToInt32(propValue) = 0} continue;

// Получаем имя значения

string name = Enum.GetName(propType, propValue);

// Получаем список свойств

Fieldlnfo fi = propType.GetField(name);

// Пытаемся получить атрибут Description DescriptionAttribute da = (DescriptionAttribute) Attribute.GetCustomAttribute(

fi, typeof(DescriptionAttribute));

// Если атрибут Description есть, то берем // его значение как имя свойства if {da != null}

name = da.Description;

// Добавляем дескриптор в коллекцию outputCollection.Add(new EnumFieldDescriptor{name, propValue, propType,

context.PropertyDescriptor, context.Instance)};

}

// Получаем коллекцию дескрипторов return new PropertyDescriptorCollection( outputCollection.ToArrayO ) ;

// Специальный класс дескриптора значения перечисления

private class EnumFieldDescriptor : PropertyDescriptor

{

private string name;

private long value;

private Type enumType;

private PropertyDescriptor parentProp;

private object parentComp;

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

internal EnumFieldDescriptor(

string name, object value, Type enumType,

PropertyDescriptor parentProp, object parentComp) : base(name, null)

{

this.name = name;

this.value – Convert.ToInt?4(value); this.enumType = enumType; this.parentProp = parentProp; this.parentComp = parentComp;

}

// Возможность сброса значения

public override bool CanResetValue(object component) {

return true;

}

11 Тип компонента

public override Type ComponentType

{

get [ return enumType; }

}

// Метод GET

public override object GetValue(object component} [

long val = Convert.ToInt64(component); return (val & value) > 0;

}

// Метод SET

public override void Setvalue(object component, object value)

{

long val = Convert.ToInt32(component); if ((bool) value)

parentProp.SetValue{parentComp,

Enum.ToObject(enumType, val | this.value));

else

parentProp.SetValue{parentComp,

Enum.ToObject(enumType, val & -this.value)!? OnValueChanged(this, EventArgs.Empty);

}

// Возможность редактирования

public override bool isReadOnly {

get { return false; )

}

// Тип свойства

public override Type PropertyType {

get { return typeof(bool); }

}

// Метод сброса

public override void ResetValue(object component) {

SetValue(component, false);

}

11 Выключить сериализацию

public override bool ShouldSerializeValue(object component) {

return false;

}

)

}

)

Рис. 8.8. Вид редактора флагов

Литература:

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

По теме:

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