|
Прошел курс. Получил код Dreamspark. Ввожу код на сайте, пишет: Срок действия этого кода проверки уже истек. Проверьте, правильно ли введен код. У вас осталось две попытки. Вы также можете выбрать другой способ проверки или предоставить соответствующие документы, подтверждающие ваш академический статус.
Как активировать код? |
Опубликован: 25.03.2010 | Доступ: свободный | Студентов: 1448 / 158 | Оценка: 4.31 / 4.00 | Длительность: 25:42:00
Тема: Программирование
Специальности: Программист, Архитектор программного обеспечения
Лекция 17:
Пользовательские элементы управления
Комбинирование готовых элементов управления
Всегда пользовательский элемент управления лучше создавать на основе уже существующих, преимущественно библиотечных, элементов управления, которые хорошо отлажены и работают привычным образом. В предыдущих примерах мы усовершенствовали библиотечный класс Button, приспосабливая его к нашим задачам путем расширения в другом классе.
Теперь мы разработаем свой элемент управления на основе нескольких библиотечных элементов. Применим прием многоэтапного последовательного расширения классов на основе наследования.
using System;
using System.Drawing;
using System.Windows.Forms;
namespace Test
{
//******************************************************
// Кнопка, генерирующая множество событий Click
// При нажатии и удержании на ней курсора мыши
class ClickmaticButton : Button
{
// Определяем поля класса
// Создаем таймер
Timer timer = new Timer();
// Задержка срабатывания кнопки Button после нажатия мыши
int iDelay = 250 * (1 + SystemInformation.KeyboardDelay);
// Скорость для срабатывания таймера, генерирующего события повторных
// нажатий кнопки компонента при удержании нажатой левой кнопки мыши
int iSpeed = 405 - 12 * SystemInformation.KeyboardSpeed;
// Конструктор
public ClickmaticButton()
{
timer.Tick += TimerOnTick;// Подписались на тики
}
// Перехватываем нажатие левой кнопки мыши и запускаем таймер
// для генерации событий Click кнопки Button
protected override void OnMouseDown(MouseEventArgs args)
{
base.OnMouseDown(args);
// Если нажата левая кнопка мыши
if ((args.Button & MouseButtons.Left) != 0)
{
timer.Interval = iDelay;// Задержка до первого тика
timer.Start();// Включили таймер
}
}
// Отработка тиков
void TimerOnTick(object sender, EventArgs e)
{
// Программно генерируем повторное
// нажатие Button при каждом тике
this.OnClick(EventArgs.Empty);
// Меняем скорость таймера
timer.Interval = iSpeed;
}
// Контролируем, находится ли нажатый курсор мыши
// над кнопкой и управляем приостановкой таймера
protected override void OnMouseMove(MouseEventArgs args)
{
base.OnMouseMove(args);
// Приостанавливаем таймер
timer.Enabled = this.Capture &&
this.ClientRectangle.Contains(args.Location);
}
// При отпускании кнопки таймер останавливаем
protected override void OnMouseUp(MouseEventArgs args)
{
base.OnMouseUp(args);
timer.Stop();
}
}
//******************************************************
// Рисование на генерирующей событие Click кнопке
// изображения стрелки
class ArrowButton : ClickmaticButton
{
// Поле для хранения ориентации кнопки
// По умолчанию острый угол треугольника направлен вправо
ScrollButton scrollButton = ScrollButton.Right;
// Конструктор
public ArrowButton()
{
// Задание стиля кнопки как не получающей фокус ввода
this.SetStyle(ControlStyles.Selectable, false);
}
// Свойство для поддержки переменной перечисления
public ScrollButton ScrollButton
{
get { return scrollButton; }
set
{
scrollButton = value;
this.Invalidate();// Перерисовать
}
}
// Переопределяем метод отрисовки кнопки
protected override void OnPaint(PaintEventArgs args)
{
Point point = PointToClient(Control.MousePosition);
bool mouseInButton = this.Capture &&
this.ClientRectangle.Contains(point);
ButtonState state = mouseInButton ?
ButtonState.Pushed : ButtonState.Normal;
state = !this.Enabled ?
ButtonState.Inactive : state;
Graphics gr = args.Graphics;
// Рисуем кнопку с треугольником внутри
ControlPaint.DrawScrollButton(
gr,
this.ClientRectangle,
scrollButton,
state);
}
protected override void OnMouseCaptureChanged(EventArgs args)
{
base.OnMouseCaptureChanged(args);
this.Invalidate();// Перерисовать
}
}
//******************************************************
// Самодельный элемент управления - поле с кнопками
public class NumericScan : UserControl
{
// Объявили событие
public event EventHandler ValueChanged;
// Объявили ссылки-поля для видимости объектов
TextBox txtBox;
ArrowButton btn1, btn2;
// Объявили базовые закрытые поля для открытых свойств
int iDecimalPlaces = 0;
decimal mValue = 0;
decimal mIncrement = 1;
decimal mMinimum = 0;
decimal mMaximum = 100;
// Доступные свойства-обертки полей
public int DecimalPlaces
{
get { return iDecimalPlaces; }
set { iDecimalPlaces = value; }
}
public decimal Value
{
get { return mValue; }
set { txtBox.Text = ValueToText(mValue = value); }
}
public decimal Increment
{
get { return mIncrement; }
set { mIncrement = value; }
}
public decimal Minimum
{
get { return mMinimum; }
set
{
// Заодно отслеживаем диапазон Value
if (Value < (mMinimum = value))
Value = mMinimum;
}
}
public decimal Maximum
{
get { return mMaximum; }
set
{
// Заодно отслеживаем диапазон Value
if (Value > (mMaximum = value))
Value = mMaximum;
}
}
// Конструктор
public NumericScan()
{
txtBox = new TextBox();
txtBox.Parent = this;
// Текст у правой границы поля
txtBox.TextAlign = HorizontalAlignment.Right;
txtBox.Text = ValueToText(mValue);// Инициализируем
txtBox.TextChanged += TextBoxOnTextChanged;
// При вводе Enter обновить Value элемента
txtBox.KeyDown += TextBoxOnKeyDown;
// Не принимать лишние символы
txtBox.KeyPress += new KeyPressEventHandler(txtBox_KeyPress);
btn1 = new ArrowButton();
btn1.Parent = this;
// Ориентация треугольничка влево
btn1.ScrollButton = ScrollButton.Left;
btn1.Click += ButtonOnClick;
btn2 = new ArrowButton();
btn2.Parent = this;
// Ориентация треугольничка вправо
btn2.ScrollButton = ScrollButton.Right;// По умолчанию
btn2.Click += ButtonOnClick;
}
string ValueToText(decimal mValue)
{
// Возвращаем с форматированием
return mValue.ToString("F" + iDecimalPlaces);
}
// Обработчик события изменения содержимого текстового поля
void TextBoxOnTextChanged(object sender, EventArgs args)
{
try
{
// Преобразуем текст в число
mValue = Decimal.Parse(txtBox.Text);
}
catch { }// На исключения не реагируем
}
// Обрабатывает каждую клавишу, но ждет клавишу Enter
void TextBoxOnKeyDown(object sender, KeyEventArgs args)
{
switch (args.KeyCode)
{
// При нажатии Enter генерируем наше событие ValueChanged
case Keys.Enter:
OnValueChanged(EventArgs.Empty);
break;
}
// Обнаруживаем цифру
isNumeric =
// Основная клавиатура
args.KeyCode >= Keys.D0 && args.KeyCode <= Keys.D9
// Дополнительная клавиатура
|| args.KeyCode >= Keys.NumPad0 &&
args.KeyCode <= Keys.NumPad9
// Клавиша BackSpace
|| args.KeyCode == Keys.Back;
}
// Отфильтровываем лишние символы из поля ввода
bool isNumeric;// Видимое поле
void txtBox_KeyPress(object sender, KeyPressEventArgs args)
{
if (isNumeric != true)// Пропускаем только цифры
args.Handled = true;// Не принимаем в TextBox
}
// Срабатывает автоматически и устанавливает
// размеры компонента this.Width, this.Height
public override Size GetPreferredSize(Size proposedSize)
{
const float weight = 1.2f;// Вес ширины
// Высота компонента
int height = txtBox.PreferredHeight +
SystemInformation.HorizontalScrollBarHeight;
// Устанавливаем размеры компонента
return new Size((int)(weight * height), height);
}
// Срабатывает автоматически, позиционирует
// кнопки и устанавливает их размеры
protected override void OnResize(EventArgs args)
{
base.OnResize(args);
txtBox.Height = txtBox.PreferredHeight;
txtBox.Width = this.Width;// Текстовое поле по ширине компонента
btn1.Location = new Point(0, txtBox.Height);// Слева снизу
btn2.Location = new Point
(this.Width / 2, txtBox.Height);// Середина низ
// Приравниваем значения полей структур
btn1.Size = btn2.Size = new Size(txtBox.Width / 2,
this.Height - txtBox.Height);
}
// Когда элемент управления уходит из фокуса ввода, надо
// проверить введенное и сгенерировать событие ValueChanged
protected override void OnLeave(EventArgs args)
{
base.OnLeave(args);
this.OnValueChanged(EventArgs.Empty);// Аргумент не используется
}
// Изменения величины пользователем по щелчкам мыши
void ButtonOnClick(object sender, EventArgs e)
{
// Если не было, то дать фокус тексовому полю
if (!txtBox.Focused)
txtBox.Focus();
// Повышаем полномочия ссылки
ArrowButton btn = sender as ArrowButton;
// Пробная величина для изменения значения на шаге
decimal mNewValue = Value;
// Выявляем кнопку и проверяем выход за границу
if (btn == btn1)
if ((mNewValue -= Increment) < Minimum)
return;
if (btn == btn2)
if ((mNewValue += Increment) > Maximum)
return;
// Принимаем изменение и вызываем обработчик,
// который сгенерирует событие ValueChanged
Value = mNewValue;
OnValueChanged(EventArgs.Empty);
}
// Ввели свою дополнительную функцию
// Изменение величины прямым вводом в текстовое поле
protected virtual void OnValueChanged(EventArgs args)
{
// Последовательно проверяем выход величины за левую и правую
// границы, и если выходит за границу, то обрезаем по границе
Value = Math.Min(Maximum, Value);
Value = Math.Max(Minimum, Value);
//Value = Decimal.Round(Value, DecimalPlaces);
// Генерируем событие
if (ValueChanged != null)
ValueChanged(this, args);
}
}
//******************************************************
// Тест для проверки нашего элемента управления
class MyClass : Form
{
// Внутренние поля для видимости в методах
Label lbl1, lbl2;// Заполняются обработчиком события ValueChanged
NumericScan numscan1, numscan2;// Ссылки на компоненты
public MyClass()
{
this.Text = "Тест пользовательского компонента";
// Размеры формы
this.Width = (int)(1.3f * this.Width);
this.Height = (int)(.8f * this.Height);
FlowLayoutPanel flow = new FlowLayoutPanel();
flow.Parent = this;// Привязали к форме
// Размещение по столбцам
flow.FlowDirection = FlowDirection.TopDown;
// Внутреннее обрамление в пикселах
flow.Padding = new Padding(20);
// Растянули по форме
flow.Dock = DockStyle.Fill;
numscan1 = new NumericScan();
numscan1.Parent = flow;
numscan1.AutoSize = true;
// Элементы между собой выравнивать по центру
numscan1.Anchor = AnchorStyles.None;
numscan1.ValueChanged += NumericScanOnValueChanged;
lbl1 = new Label();
lbl1.Parent = flow;
lbl1.AutoSize = true;
// Элементы между собой выравнивать по центру
lbl1.Anchor = AnchorStyles.None;
// Пустая текстовая метка для отступа элементов
(new Label()).Parent = flow;
numscan2 = new NumericScan();
numscan2.Parent = flow;
numscan2.AutoSize = true;
// Элементы между собой выравнивать по центру
numscan2.Anchor = AnchorStyles.None;
numscan2.ValueChanged += NumericScanOnValueChanged;
lbl2 = new Label();
lbl2.Parent = flow;
lbl2.AutoSize = true;
// Элементы между собой выравнивать по центру
lbl2.Anchor = AnchorStyles.None;
// Сами принудительно выполняем обработчик
// для начальной инициализации текстовых меток
NumericScanOnValueChanged(numscan1, EventArgs.Empty);
NumericScanOnValueChanged(numscan2, EventArgs.Empty);
}
void NumericScanOnValueChanged(object sender, EventArgs args)
{
NumericScan ob = sender as NumericScan;// Приводим ссылку
if (ob == numscan1)
lbl1.Text = "Первый: " + numscan1.Value;
else if (ob == numscan2)
lbl2.Text = "Второй: " + numscan2.Value;
}
}
//******************************************************
// Запуск
class Program
{
static void Main()
{
Application.EnableVisualStyles();
// Создали форму и запустили цикл сообщений Windows
Application.Run(new MyClass());
}
}
}
Листинг
17.13 .
Пример разработки пользовательского элемента управления