Главная » C#, Компоненты » Выпадающий диалог

0

Как я уже говорил, выпадающий диалог оформляется в виде визуального компонента (наследника класса control) и регистрируется с помощью вызова метода сервиса DropDownControl (myEditorcontroi). Диалог обычно закрывается, когда пользователь выберет новое значение или откажется от выбора (например, нажмет клавишу <Esc>). Программное закрытие окна можно выполнить, вызвав метод CloseDropDown () .

Стандартный прототип компонента редактирования можно описать так: О метод SetvaiueO устанавливает текущее значение свойства; ? метод GetvaiueO возвращает значение свойства после редактирования. Если значение не изменилось, метод должен вернуть старое значение;

П событие onvaiuechanged (). В обработчике этого события, редактор типа может вызвать метод cioseDropDown 1) и закрыть редактор сразу после установки нового значения свойства. Соответствующий код выглядит примерно так:

MyEditorControl editor = new MyEditorControl();

editor.ValueChanged += new EventHandler(this.ValueChanged);

editor.SetValue(value);

edSvc.DropDownControl(editor);

value — editor.GetValue();

Обработчик ValueChanged очень простой:

private void ValueChanged(object sender, EventArgs e)

{

if (edSvc !- null) {

edSvc.CioseDropDown();

}

}

Для сложных свойств, значение или отображение которых зависит от других свойств компонента, простого значения value мало и можно использовать сам редактируемый компонент, возвращаемый значением instance параметра context метода Editvalue ():

public override object EditValue(ITypeDescriptorContext context,

IServiceProvider provider, object value)

{

if (context != null && context.Instance != null && provider != null) (

// Редактируемый компонент

MyComponent propValue — (MyComponent) context.Instance;

}

}

В качестве примера я сделал небольшой компонент "прогресс" (листинг 9.1), Он имеет всего три свойства: Min, мах и Position. Первые два задают границы некоторого значения, a Position — текущее значение. Компонент отображает это значение с помощью заполнения прямоугольника цветом (рис. 9.6). Без дополнительного редактора типа все три свойства этого компонента будут видны как обычные числовые свойства. Задача состоит в том, чтобы свойство Position можно было редактировать более удобно и просто. Или.

другими словами, нужно сделать редактор типа PositionuiEditor для свойст-

аа Position:

[Editor (typeof (PositionuiEditor) , typeof (UlTypeEditor)) ] public int Position

}

get/set

}

Рис. 9.6. Вид компонента MinMaxControl

Класс PositionuiEditor реализован no приведенному выше шаблону (лис- тинг9.2). Метод GetEditstyleO возвращает значение UlTypeEditorEditstyle. DropDown, означающее, что редактор будет выглядеть как выпадающий список. В методе EditvaiueO нам потребуется компонент, который будет являться редактором свойства. Вид самого редактируемого компонента нам вполне подходит, поэтому было бы логично сделать наследника компонента MinMaxControl и реализовать в нем необходимую функциональность (листинг 9.3):

О конструктор должен обязательно устанавливать размеры компонента. Ширина редактора будет определяться шириной редактора свойств, а вот высота будет определена самим компонентом (если не включено разрешение "изменять размеры диалога");

О метод OnMouseDown() позволит устанавливать новое значение, отмечая позицию на компоненте (метод setNewvaiue ());

О событие ValueChanged будет вызываться при выборе значения и позволит закрыть окно диалога редактирования сразу после выбора значения (обработчик editorControl_valueChanged В классе PositionuiEditor). Вид получившегося редактора показан на рис. 9.7. Если перекрыть свойство isDropDownResizabie и возвращать true, то редактор будет иметь возможность изменять размер (рис. 9.8):

public override bool IsDropDownResizable

f

get

{

return true;

}

}

Рис. 9.7. Вид редактора свойства

Position

Рис. 9.8. Вид редактора свойства Position, если IsDropDownResizable возвращает true

Листинг 9 1. Компонент MinbUxControl

using System;

using System.Collections.Generic;

using System.Text;

using System.Windows.Forms;

us ing Sys tem.Drawi ng;

using System.ComponentModei;

using System.Drawing.Design;

namespace MyControl {

public class MinMaxControl : Control {

private int min = 0; private int max = 100; private int position = 50;

[Description("MHHHMyM")] [DefaultValue(0)]

public int Min {

get { return min; }

set { min = value; Invalidate{); }

]

[Description("MaKCMMyM")] [DefaultValue(100)]

public int Max (

get { return max; }

set { max = value; Invalidate(); }

}

[Description("Текущее положение")]

[Editor(typeof(PositionUIEditor), typeof(UITypeEditor))] public int Position (

get { return position; )

set { position = value; Invalidate(); }

}

// Отрисовка

protected override void OnPaint(PaintEventArgs e) (

base.OnPaint [e);

if (Min != Max) (

SolidBrush fillBrush = new SolidBrush(Color.Blue); SolidBrush backBrush = new SolidBrush(this.BackColor);

// Рисуем прямоугольник

Rectangle nonFillPart = ClientRectangle;

float percentValue =

((float)Position / ((float)Max- (float)Min)); int nonDimLength =

(int)(percentValue * (float)nonFillpart.Width); nonFillPart.X += nonDimLength; nonFillPart.Width -= nonDimLength; // Заливаем весь компонент

e.Graphics.FillRectangle(fillBrush, ClientRectangle); // Восстанавливаем цвет в незаполненной части е.Graphics.FillRectangle(backBrush, nonFillPart};

fillBrush.Dispose(); backBrush.Dispose(};

}

// Рамка

Rectangle rect = ClientRectangle;

e.Graphics.DrawRectangle(SystemPens.windowText,

rect.X, rect.Y, rect.width – 1, rect.Height – 1);

}

)

}

Листинг 9 2 Редактор типа для свойства Рил!1, l у

using System;

using System.Collections.Generic; using System.Text; using System.Drawing.Design; using System.ComponentModel; using System.Windows.Forms.Design;

namespace MyControl (

class PositionuiEditor : UITypeEditor

{

private IWindowsFormsEditorService edSvc = null;

// Стиль редактора — выпадающий диалог

public override UITypeEditorEditStyle GetEditStyle(

System.ComponentModel.ITypeDescriptorContext context)

{

return UITypeEditorEditStyle.DropDown;

}

public override object EditValue(ITypeDescriptorContext context, IServiceProvider provider, object value)

{

if (context ‘.= null &&

context.Instance != null && provider != null)

{

// Получаем интерфейс сервиса edSvc = (IWindowsFormsEditorService)

provider.GetService(typeof(IWindowsFormsEditorService)); if (edSvc !— null) (

// Создаем компонент для редактирования PositionEditorControl editorControl =

new PositionEditorControl();

// Подписываемся на получение уведомлений // рб изменении значения editor-Control. ValueChanged +=

new EventHandler(editorControl_ValueChanged); // Текущий редактируемый компонент MinMaxControl currentControl =

context.Instance as MinMaxControl;

// Устанавливаем свойства и текущее // значение для редактирования editorControl.Min = currentControl.Min; editorControl.Max = currentControl.Max; editorControl.Position = (int)value;

// Вызываем DropDownControl

edSvc.DropDownControl(editorControl);

// Получаем новое значение value = editorControl.Position;

}

}

// Возвращаем либо старое, либо новое значение return value;

}

// Вызывается при изменении значения свойства // в редакторе типа

void editorControl_ValueChanged(object sender, EventArgs e)

E

if (edSvc != null}

{

// Закрыть редактор edSvc.CloseDropDown();

}

}

}

}

Листинг 9 3 Компонент для редактора типа для своистпа Lo«-it-ion

using System;

using System.Collections.Generic; using System. Text;

using System.Windows.Forms; using Systems-Drawing;

namespace MyControl {

class PositionEditorControl : MinMaxControl {

11 Событие, которое будет вызываться при изменении значения. // Означает, что пользователь выбрал новое значение, private EventHandler onValueChanged; public event EventHandler ValueChanged (

add

onValueChanged += value;

}

remove (

onValueChanged -= value;

}

}

// В конструкторе надо задать размеры public PositionEditorControl() (

this.Size = new System.Drawing.Size(100, 15);

}

// Пользователь выбирает новое значение щелчком мыши protected override void OnMouseDown{MouseEventArgs e) (

base.OnMouseDown(e); SetNewValue(new Point(e.X, e.Y));

}

// Вычислить и установить новое значение свойства private void SetNewValue(Point pointClick) (

if (ClientRectangle.Contains(pointClick)) (

float percentage =

(float)pointClick.X / (float)ClientRectangle.Width;

Position = (int) (percentage * (float) (Max — Min)); OnValueChanged(EventArgs.Empty);

}

}

// Вызывается при изменении значения свойства // Позволяет редактору типа закрыть редактирование

protected void OnValueChanged(EventArgs e) {

if (onValueChanged != null) {

onValueChanged.Invoke(this, e);

}

}

}

}

В заключение раздела замечу, что параметр context имеет еще несколько полезных вещей:

?          методы OnComponent Changing И OnComponentChanged ПОЗВОЛЯЮТ уВвДОМИТЬ дизайнер о начале и завершении изменения свойств компонента;

?          свойство PropertyDescriptor предоставляет доступ к дескриптору редактируемого свойства.

В следующем разделе я расскажу о редакторе в виде модального диалога.

Литература:

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

По теме:

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