Опубликован: 13.07.2010 | Доступ: свободный | Студентов: 889 / 20 | Оценка: 4.40 / 4.20 | Длительность: 77:34:00
Самостоятельная работа 27:

Разработка комбинированного компонента

Упражнение 1. Разработка кнопки ClickmaticButton

  • Добавьте к решению MySolution новый пустой проект командой File/Add/New Project и заполните окно мастера так

  • В панели Solution Explorer для корневого узла проекта UserControls выполните команду Properties контекстного меню и настройте вкладку Application свойств проекта следующим образом

  • В панели Solution Explorer вызовите для корневого узла проекта UserControls контекстное меню и командой Add/Component добавьте элемент ClickmaticButton

  • В панели Solution Explorer для узла References проекта UserControls, где уже должна находиться ссылка на библиотечную сборку System, выполните команду Add Reference
  • Удерживая клавишу Ctrl через окно Add Reference выделите и добавьте к проекту UserControls ссылки на библиотечные сборки System.Drawing и System.Windows.Forms


  • Убедитесь, что теперь узел References проекта UserControls стал выглядеть так


  • Переведите файл ClickmaticButton.cs [Design] в режим редактирования кода командой контекстного меню View Code
  • Добавьте в начало файла ClickmaticButton.cs необходимые инструкции using подключения нужных нам пространств имен и замените базовый класс Component на Button, чтобы код файла стал таким
using System;
using System.ComponentModel;
using System.Drawing;
using System.Windows.Forms;
    
namespace MyCompany.StudName
{
    public partial class ClickmaticButton : Button // : Component
    {
        public ClickmaticButton()
        {
            InitializeComponent();
        }
    
        public ClickmaticButton(IContainer container)
        {
            container.Add(this);
    
            InitializeComponent();
        }
    }
}
Листинг 19.5. Модификация файла ClickmaticButton.cs

Мы создали заготовку расширения библиотечного класса кнопки с целью изменить ее функциональность таким образом, чтобы в нажатом состоянии кнопка генерировала имитацию щелчков пользователя.

Наполнение класса ClickmaticButton функциональностью генерации щелчков мыши

  • Выполните команду контекстного меню View Designer и поместите из свитка Components панели Toolbox на форму ClickmaticButton.cs [Design] компонент Timer. Присвойте созданному экземпляру имя timer
  • Двойным щелчком на экземпляре timer создайте обработчик timer_Tick()
  • Добавьте в класс ClickmaticButton два поля целого типа для задания задержки на момент запуска таймера и интервала повторения тиков. Для этого используйте соответствующие библиотечные свойства класса System.Windows.Forms.SystemInformation, предусмотренные для управления клавиатурой
public partial class ClickmaticButton : Button // : Component
    {
        .....................................................
    
        // Поля характеристик работы таймера 
        readonly int DELAY = 250 * (1 + SystemInformation.KeyboardDelay);
        readonly int SPEED = 405 - 12 * SystemInformation.KeyboardSpeed;
    
        private void timer_Tick(object sender, EventArgs e)
        {
    
        }
    }
Листинг 19.6. Добавление к классу ClickmaticButton полей-характеристик таймера

Ключевое слово readonly дает указание компилятору следить за тем, чтобы где-нибудь в коде мы случайно не попытались повторно переприсвоить этим полям новое значение. Оно позволяет выполнить отложенную инициализацию один раз, причем можно вычислимым выражением в любом методе класса. Ключевое слово const требует немедленной инициализации переменной, причем константной величиной, что в данном случае нам не подходит.

  • Начав ввод с ключевого слова override, переопределите в классе ClickmaticButton унаследованный метод OnMouseMove() для управления приостановкой работы таймера, когда курсор при наличии установленной связи "разрабатываемый элемент кнопки - устройство мыши" будет выведен пользователем за пределы области чувствительности элемента кнопки
// Переопределение унаследованного метода диспетчеризации 
        // события MouseMove увода курсора за область чувствительности элемента
        protected override void OnMouseMove(MouseEventArgs mevent)
        {
            base.OnMouseMove(mevent);
    
            // Приостанавливаем или возобнавляем запущенный таймер логическим выражением
            timer.Enabled = this.Capture  // Связь с мышью установлена
                // && (MouseButtons & MouseButtons.Left) != 0   // Распознавать левую кнопку необязательно
                && this.ClientRectangle.Contains(mevent.Location);   // Курсор над кнопкой 
                // && this.ClientRectangle.Contains(this.PointToClient(MousePosition))// То же самое!
        }
Листинг 19.7. Приостановка таймера при уводе курсора
  • Начав ввод с ключевого слова override, переопределите в классе ClickmaticButton унаследованный метод OnMouseDown() диспетчеризации события MouseDown для запуска таймера при нажатии левой кнопки мыши
// Переопределение унаследованного метода диспетчеризации 
        // события MouseDown нажатия кнопки мыши для запуска таймера
        protected override void OnMouseDown(MouseEventArgs mevent)
        {
            base.OnMouseDown(mevent);   // Отправляем к базовому методу
    
            // Если нажата левая кнопка мыши (побитовое умножение)
            if ((mevent.Button&MouseButtons.Left) != 0)
            {
                timer.Interval = DELAY;     // Задержка для момента нажатия
                timer.Start();              // Запустить таймер
            }
        }
Листинг 19.8. Переопределение метода диспетчеризации события MouseDown

Если мы не отправим вызов перехваченного виртуального метода далее к базовому классу, то хоть таймер и запустится, но интерфейс кнопки не будет меняться привычным для пользователя образом и подписанные на событие MouseDown обработчики не сработают. Запущенный таймер до первого срабатывания выдержит паузу DELAY, затем начнет вызывать обработчик timer_Tick(), в котором мы установим новый интервал срабатывания SPEED и будем принудительно вызывать метод диспетчеризации события Click элемента кнопки, имитируя тем самым генерацию щелчков пользователя на нем.

  • Заполните ранее созданный обработчик timer_Tick() тиков таймера следующим кодом
private void timer_Tick(object sender, EventArgs e)
        {
            timer.Interval = SPEED; // Устанавливаем новый интервал генерации тиков
            this.OnClick(EventArgs.Empty);  // Генерируем щелчок на элементе кнопки
                                            // с пустым фактическим параметром
        }
Листинг 19.9. Обработчик timer_Tick() тиков таймера в классе ClickmaticButton

Остановку запущенного таймера и, соответственно, прекращение генерации щелчков пользователя на элементе кнопки предусмотрим в переопределении метода OnMouseUp() диспетчеризации события MouseUp отпускания кнопки мыши.

  • Начав ввод с ключевого слова override, переопределите в классе ClickmaticButton унаследованный метод OnMouseUp() диспетчеризации события MouseUp для остановки таймера при отпускании кнопки мыши
// Переопределение унаследованного метода диспетчеризации 
        // события MouseUp отпускания кнопки мыши для остановки таймера
        protected override void OnMouseUp(MouseEventArgs mevent)
        {
            base.OnMouseUp(mevent);     // Отправляем к базовому методу
    
            timer.Stop();   // Стоп таймер
        }
Листинг 19.10. Переопределение метода диспетчеризации события MouseUp

На этом функциональность компонента кнопки с генерацией серии событий щелчков на нем мы закончили. Далее мы выполним еще одно расширение класса ClickmaticButton, чтобы нарисовать на кнопке стрелку. Для изменения направления стрелки предусмотрим открытое свойство ScrollButton. Но прежде, чем двигаться дальше, проверим работоспособность сконструированного расширения кнопки.