Практикум прикладного программирования на C# в среде VS.NET 2005

Пользовательский интерфейс Windows Forms для C#

Разбить на страницы
Показывать лекцию целиком

Файлы к лабораторной работе Вы можете скачать здесь.

В данной лабораторной работе мы рассмотрим некоторые возможности интегрированной среды разработки программного обеспечения ( IDE - Integrated Development Environment ) Visual Studio.NET 2005. Мы будем использовать разработанный корпорацией Microsoft самый красивый и современный язык программирования C# (Си-шарп). Мы будем опираться на мощную библиотеку классов .NET Framework ( FCL - Framework Class Library, она же BCL - Basic Class Library).

Создание заготовки приложения

  • Выполните команду File/New/Project оболочки для создания нового проекта
  • В диалоговом окне New Project выберите кнопкой Browse папку для размещения проекта, задайте тип, шаблон и имя проекта WinFormsApp
  • После щелчка на кнопке OK мастер создаст заготовку приложения и выведет в режиме дизайна пустую форму, которая при запуске приложения будет представлять окно. Стандартный размер сгенерированной формы равен 300x300. Сделаем эту форму стартовой и разместим на ней элементы управления для вызова дочерних форм, реализующих отдельные упражнения данной работы.

  • Откройте панель Solution Explorer оболочки и переименуйте файл Form1.cs в файл Start.cs
  • Щелкните на форме правой кнопкой мыши и выполните команду контекстного меню View Em, чтобы вызвать представление файла Start.cs в режиме редактора кода
  • В режиме кода вызовите комбинацией клавиш Ctrl-F окно Find and Replace для замены всех вхождений Form1 на Start. После заполнения полей поиска и замены щелкните на кнопке Replace All
  • В раскрывающемся списке Members выделите функцию InitializeComponent(), чтобы быстро позиционироваться в соответствующее место кода
  • Отредактируйте в функции InitializeComponent() код установки заголовка окна в режиме выполнения
  • private void InitializeComponent()
        {
                this.components = new System.ComponentModel.Container();
                this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
                this.Text = "Lab38 - Снетков";
        }

    Установка пароля на главное окно приложения

    Теперь давайте добавим к главной форме Start код поддержки пароля при запуске приложения. Для этого нам потребуется диалоговое окно с текстовым полем. Сконструируем его. Создание диалогового окна будет состоять из трех шагов:

  • Создание самой формы диалогового окна (класс InputPassword )
  • Размещение на форме интерфейсных элементов пользователя
  • Создание кода, управляющего диалоговым окном
  • В панели Solution Explorer выделите корневой узел проекта и командой Add/Windows Form добавьте в проект файл формы с именем InputPassword.cs
  • Удалите из узла References лишние добавленные мастером ссылки на библиотечные сборки System.Data и System.Xml
  • Откройте файл InputPassword.cs в режиме View Code и удалите инструкции using подключения пространств имен System.Data и System.Xml
  • Настройте форму InputPassword в соответствии с таблицей
  • Таблица свойств формы InputPassword
    Свойство Значение Пояснения
    StartPosition CenterScreen Открывать в центре экрана
    FormBorderStyle FixedDialog Запретить пользователю менять размер
    MaximizeBox false Отключить системную кнопку развертывания
    MinimizeBox falseStandardDialogs Отключить системную кнопку свертывания
    ShowInTaskbar false Запретить появление в панели задач
    AutoSize true Подстраиваться под содержимое
    AutoSizeMode GrowAndShrink Подстраиваться под содержимое (расширяться и сжиматься)
    Text Пусто Заголовок окна
  • Из свитка Containers панели инструментов Toolbox поместите на форму компоновочную панель FlowLayoutPanel и настройти ее в соответствии с таблицей
  • Таблица свойств компоновочной панели FlowLayoutPanel
    Свойство Значение Пояснения
    Name flow Имя компоновочной панели
    AutoSize true Подстраиваться под содержимое
    FlowDirection TopDown Размещать сверху вниз
    WrapContents false Не переносить дочерние элементы в следующий столбец
    Padding.All 8 Внутренний отступ дочерних элементов по периметру окна
    Dock Fill Распахнуть на всю клиентскую область родителя (формы)

    Эта панель будет автоматически следить за размещением своих дочерних элементов в соответствии с настройками.

  • Выделите на форме компоновочную панель flow, чтобы именно она принимала дочерние элементы, поместите в нее из свитка Common Controls текстовую метку Label и настройте ее свойства в соответствии с таблицей
  • Таблица свойств текстовой метки Label
    Свойство Значение Пояснения
    Name lblMessage Имя текстовой метки
    AutoSize true Подстраиваться под содержимое
    Anchor None Расположить посредине
    Margin.All 8 Отступ по наружному периметру текстовой метки
  • Аналогичным образом поместите в панель flow последовательно экземпляры компонентов TextBox и Button, которые настройте так
  • Таблица свойств поля ввода TextBox
    Свойство Значение Пояснения
    Name txtInput Имя текстовой метки
    Anchor None Расположить посредине
    Margin.All 8 Отступ по наружному периметру текстовой метки
    PasswordChar * Эхо ввода в текстовом поле

    Таблица свойств кнопки Button
    Свойство Значение Пояснения
    Name btnOk Имя кнопки
    AutoSize true Подстраиваться под содержимое
    Anchor None Расположить посредине
    Margin.All 8 Отступ по наружному периметру кнопки
    Text OK Надпись
    DialogResult OK Назначить статус "кнопки OK" в родительской форме

    Свойству дочерних кнопок формы DialogResult можно присвоить любое значение из перечисления System.Windows.Forms.DialogResult ( Abort, Cancel, Ignore, No, None, OK, Retry, 25_73 ). Оно и будет возвращено функцией ShowDialog() формы, если пользователь выберет именно эту кнопку. Если свойству DialogResult кнопки будет присвоен статус, отличный от None, то при щелчке пользователя на такой кнопке форма будет автоматически закрываться.

  • Подтяните низ формы до приемлемого размера, чтобы она стала выглядеть примерно так
  • Откройте файл InputPassword.cs в режиме View Designer, щелкните на заголовке формы и выполните команду Format/Lock Controls, чтобы защитить интерфейс формы от случайных изменений. Это групповая команда, которая устанавливает свойство Locked всех дочерних визуальных элементов и самой формы в значение True. То же самое можно сделать индивидуально для каждого элемента через меню Properties
  • Мы создали сам пользовательский интерфейс класса InputPassword диалогового окна. Теперь нужно настроить класс InputPassword, добавив туда метод создания диалогового окна и вызова его на экран.

  • Модифицируйте класс InputPassword следующим образом
  • using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Drawing;
    using System.Windows.Forms;
        
    namespace WinFormsApp
    {
        public partial class InputPassword : Form
        {
            public InputPassword()
            {
                InitializeComponent();
            }
        
            public InputPassword(string windowTitle, string message)
            {
                InitializeComponent();
        
                this.Text = windowTitle;
                lblMessage.Text = message;
            }
        
            public static string Show(string windowTitle, string message)
            {
                using(InputPassword inputDlg = 
                    new InputPassword(windowTitle, message))
                {
                    inputDlg.ShowDialog();
                    return inputDlg.txtInput.Text;
                }
            }
        }
    }

    Мы создали параметризованный конструктор для ввода заголовков диалогового окна в момент его создания. Мы добавили статический метод создания диалогового окна, который возвращает значение текстового поля после щелчка пользователем на кнопке, и такой метод нужно вызывать по имени класса. Упаковка создания экземпляра формы в блок using позволяет вызвать сборщик мусора сразу после выхода из этого блока.

    Теперь нужно поместить вызов окна запроса пароля в обработчик события Load запуска формы.

  • Откройте файл Start.cs в режиме View Designer, выделите форму через ее заголовок, перейдите в панель Properties, установите ее в режим Events, найдите событие Load и создайте для него обработчик Start_Load(). Заполните обработчик события так
  • private void Start_Load(object sender, System.EventArgs e)
        {
                string password = InputPassword.Show(
                    "Окно аутентификации пользователя",
                    "Просим ввести Ваш пароль:");
                if (password != "root")// Плохой способ хранения пароля
          {
            MessageBox.Show(
              "Извините, но Вам не разрешено\n" // Сообщение
              + "пользоваться этой суперпрограммой!!!",
              "Неверный пароль", // Заголовок окна
              MessageBoxButtons.OK, // Кнопка OK
              MessageBoxIcon.Stop);// Критическая иконка
            this.Close();
          }
        }
  • Запустите приложение, диалоговое окно ввода пароля должно выглядеть так
  • При неправильном пароле появляется простое диалоговое окно сообщений

    и приложение завершит свою работу.

    Добавление списка для запуска упражнений

    На стартовой форме мы создадим список с наименованиями упражнений, который будем пополнять по мере их выполнения. В окончательном варианте работы щелчок по пункту списка должен запускать дочернюю форму, соответствующую выполненному упражнению. Это удобно при демонстрации выполненной лабораторной работы.

  • Перейдите в режим Design, откройте в панели Toolbox вкладку Common Controls и двойным щелчком на компоненте ListBox создайте на форме его экземпляр
  • Выделите объект listBox1 и в панели Properties установите для него следующие значения свойств
  • Свойства объекта ListBox формы Start
    Свойство Значение
    Name generalList
    Dock Fill
    Items 1) Простое диалоговое окно со смайликами
  • Щелкните на заголовке формы и увеличьте ее ширину за маркеры так, чтобы поместилось все предложение в списке ListBox.
  • Через раскрывающийся список вверху панели Properties выделите объект generalList и установите для нее режим Events
  • Найдите событие SelectedIndexChanged и двойным щелчком на его поле значений создайте обработчик generalList_SelectedIndexChanged()
  • Теперь мы будем добавлять к приложению новые формы для выполнения каждого нового упражнения, регистрировать их в списке и помещать вызовы упражнений в этот обработчик главной формы.

    Упражнение 1. Смайлики

  • Выполните команду Project/Add Windows Form, чтобы добавить к проекту новую форму
  • Задайте имя новой форме Smiles.cs (Улыбки)
  • Поместите на форму три компонента PictureBox из вкладки Common Controls панели Toolbox, текстовую метку Label и одну кнопку Button. Все расположите так, как показано на снимке экрана (установите свойство label1.AutoSize =false )
  • Для выравнивания компонентов пользуйтесь командами меню оболочки, входящими в категорию Format, или одноименными кнопками панели инструментов Layout

  • Выполните команду меню Format/Lock Controls, чтобы закрепить расположение интерфейсных элементов на форме и, тем самым, защитить их от случайного сдвига или изменения размеров. Обратите внимание, что теперь на выделенных элементах маркеры сменились гладкой рамкой с пиктограммой замка
  • Теперь давайте установим для помещенных на форму объектов нужные свойства через панель Properties. При этом важно понимать, что все визуальные манипуляции с формой и помещенными на нее компонентами, в том числе и установка свойств через панель Properties, - это ничто иное, как удобный и наглядный способ генерации кода с помощью графических средств оболочки. Наша работа в режиме дизайна сопровождается параллельной работой оболочки в режиме кода. И все, что можно сделать через графический режим, можно сделать и вручную через код. Более того, код, набранный нами вручную, будет менее избыточным, чем это сделает оболочка по нашим визуальным инструкциям. Но забудем про расточительство, главное - удобство, быстрота и комфорт.

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

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

  • Задайте свойства размещенных на форме объектов через панель Properties в порядке их следования слева-направо, сверху-вниз, как указано в таблице
  • Значения свойств дочерних объектов формы Smiles
    Класс Свойство Значение Пояснения
    Form Text Smiles - Упражнение №1 Заголовок окна
      FormBorderStyle FixedDialog Запретили изменение размера окна формы
      MaximizeBox False Отключили системную кнопку развертывания окна
      MinimizeBox False Запретили системную кнопку свертывания окна
    PictureBox Name picSmile Идентификатор объекта ( улыбка )
      Image FACE02.ICO (возьмите из данной работы в каталоге Source. Используйте кнопку Import для радиокнопки Local resource ) Файл рисунка
      SizeMode StretchImage Опция - растянуть рисунок по размерам объекта
    PictureBox Name picFrown Идентификатор объекта ( хмурый взгляд )
      Image FACE04.ICO (возьмите из данной работы в каталоге Source. Используйте кнопку Import для радиокнопки Local resource ) Файл рисунка
      SizeMode StretchImage Опция - растянуть рисунок по размерам объекта
    PictureBox Name picHappy Идентификатор объекта ( счастливый )
      Image FACE03.ICO (возьмите из данной работы в каталоге Source. Используйте кнопку Import для радиокнопки Local resource ) Файл рисунка
      SizeMode StretchImage Опция - растянуть рисунок по размерам объекта
    Label Name lblMessage Идентификатор объекта ( сообщение )
      Text Щелкайте на смайликах Начальное содержимое текстовой метки
      Font/Name Arial Наименование шрифта
      Font/Size 14 Размер шрифта
      Font/Bold True Полужирный
      ForeColor Red Цвет переднего плана (красный)
      TextAlign MiddleCenter Выравнивание текста - середина по вертикали, центр по горизонтали
      BorderStyle Fixed3D Объемный вид элемента
    Button Name btnExit Идентификатор объекта
      Text Выход

    Надпись на кнопке

      AutoSize true Подстраиваться под размер надписи

    После всех настроек внешний вид формы должен быть примерно таким

    Разработку интерфейса первой дочерней формы на этом можно считать завершенной. Теперь пришла пора обеспечить ее функциональность.

  • Выделите первый смайлик picSmile и через панель Properties (в режиме Events ) создайте обработчик события Click
  • Заполните обработчик следующим кодом
  • private void picSmile_Click(object sender, System.EventArgs e)
        {
          picSmile.BorderStyle = BorderStyle.FixedSingle; // Рамка
          picFrown.BorderStyle = BorderStyle.None; // Нет рамки
          picHappy.BorderStyle = BorderStyle.None; // Нет рамки
          lblMessage.Text = "Щелкнули на первом рисунке";
        }
  • Двойным щелчком на втором рисунке ( picFrown ) создайте для него обработчик, который заполните так
  • private void picFrown_Click(object sender, System.EventArgs e)
        {
          picSmile.BorderStyle = BorderStyle.None; // Нет рамки
          picFrown.BorderStyle = BorderStyle.FixedSingle; // Рамка
          picHappy.BorderStyle = BorderStyle.None; // Нет рамки
          lblMessage.Text = "Щелкнули на втором рисунке";
        }
  • Двойным щелчком на третьем рисунке ( picHappy ) создайте для него обработчик, который заполните так
  • private void picHappy_Click(object sender, System.EventArgs e)
        {
          picSmile.BorderStyle = BorderStyle.None; // Нет рамки
          picFrown.BorderStyle = BorderStyle.None; // Нет рамки
          picHappy.BorderStyle = BorderStyle.FixedSingle; // Рамка
          lblMessage.Text = "Щелкнули на третьем рисунке";
        }
  • Двойным щелчком на кнопке btnExit создайте для нее обработчик, который заполните так
  • private void btnExit_Click(object sender, System.EventArgs e)
        {
          this.Close(); // Закрыть форму
        }

    Теперь подключим вызов этой дочерней формы к движку приложения, обеспечив возможность ее вызова по щелчку на соответствующей строке списка с упражнениями.

  • Сохраните проект командой меню File/Save All и закройте все окна редактирования командой Window/Close All Documents.
  • В панели Solution Explorer щелкните правой кнопкой мыши на файле Start.cs и выполните команду контекстного меню View Designer (или откройте файл в режиме дизайна двойным щелчком левой кнопки мыши).
  • Выделите элемент списка generalList и через панель Properties щелкните два раза на имени уже созданного обработчика в поле события SelectedIndexChanged, чтобы быстро позиционироваться к заголовку кода обработчика. Заполните обработчик следующим кодом
  • private void generalList_SelectedIndexChanged(object sender, System.EventArgs e)
        {
          switch(generalList.SelectedIndex + 1)
          {
            case 1:
              Smiles  frm1 = new Smiles();
              frm1.ShowDialog();
              break;    
          }
        }

    Здесь мы применили метод ShowDialog() класса Form (вместо метода Show() ). Это позволит нам открывать дочерние формы в модальном режиме (пока не закроется очередная форма, другие окна приложения не получат фокус ввода).

  • Выделите в режиме дизайна форму Start (щелкните на заголовке окна формы) и установите через панель Properties ee свойство StartPosition в значение CenterScreen, чтобы при первом запуске она появлялась в центре экрана
  • Откройте в режиме дизайна (в панели Solution Explorer ) форму Smiles, выделите ее через заголовок окна формы и установите свойство StartPosition в значение Manual. Проследите, чтобы свойство Location (размещение) имело значение ( 0, 0 ). Тем самым мы задали позицию появления дочерней формы в верхнем левом углу экрана.
  • Два последних действия позволят нам держать форму движка в центре экрана, а дочерние формы задвинуть в начало экрана (удобно для демонстрации упражнений, полезно для тренировки).

  • Запустите приложение и проверьте его работоспособность
  • На этапе построения формы бывает полезным сразу запускать ее для проверки. В нашем случае форма Smiles может быть вызвана только из главной формы. Исправим это.

  • Добавьте в конец класса Smiles следующую функцию-член Main(), которая позволит отображать форму первой при запуске приложения
  • public class Smiles : System.Windows.Forms.Form
      {
        ..............................................................
          
        private void btnExit_Click(object sender, System.EventArgs e)
        {
          this.Close(); // Закрыть форму
        }
      
        static void Main()
        {
          Application.Run(new Smiles());
        }
      }
  • Установите в качестве стартовой форму Smiles. Для этого выполните команду меню оболочки Project/WinFormsApp Properties и в появившемся диалоговом окне установите свойство Startup Object в значение WinFormsApp.Smiles
  • Запустите приложение и убедитесь, что теперь дочерняя форма Smiles стартует первой и единственной.
  • Краткое описание части компонентов панели Toolbox

    Вкладка All Windows Forms панели Toolbox содержит все компоненты, которые необходимы для быстрой разработки интерфейса пользователя. Она становится доступной, когда форма открыта в режиме Design и текущее приложение не запущено. Режим Design и компоненты панели Toolbox - это лишь инструменты для частичной автоматизации труда программиста. С их помощью быстро и синтаксически правильно оболочка генерирует код C# приложения в файле *.cs. Все компоненты поддерживаются соответствующими классами и доступны для управления ими программным путем.

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

    Некоторые компоненты панели Toolbox
    Компонент Назначение
    Pointer Установка курсора в режим выделения объектов.
    Button Инструмент для генерирования события щелчка, по которому вызывается функция - обработчик. В эту функцию можно разместить любой код, который требуется выполнить при щелчке на этом инструменте.
    CheckBox Дает возможность пользователю установить нужный режим из двух возможных. При обединении этих элементов в тематическую группу пользователь может производить множественные настройки нашего приложения.
    CheckedListBox Множество элементов CheckBox, объединенных в скролирующую группу.
    ColorDialog Стандартное диалоговое окно для предоставления пользователю возможности выбирать цвета
    ComboBox Раскрывающийся список. Состоит из верхней части с редактируемым текстовым полем, и нижней части со списком для выбора готовых элементов.
    ContextMenuStrip Контекстные меню обычно вызываются щелчком правой кнопкой мыши на нужном элементе управления формы. Туда обычно включают часто используемые команды из основного меню приложения. Это обеспечивает быстрый доступ пользователя к таким командам.
    DataGridView Этот элемент отображает данные в виде таблицы, состоящей из строк и столбцов. В простейшем случае этот элемент просто отображает все данные связанной с ним одной таблицы базы данных без всяких условий и позволяет оперировать с ними как в обычной электронной таблице. В более сложном случае элемент отображает выборку данных из нескольких связанных таблиц по некоторым условиям.
    DateTimePicker Этот элемент дает возможность пользователю быстро выбирать нужные дату из предоставляемого удобного интерфейса в виде календаря.
    DomainUpDown Представляет собой текстовое поле со стрелками для изменения значений списка вверх или вниз.
    ErrorProvider Этот элемент управления (невизуальный компонент) применяется для проверки правильности пользовательского ввода в допустимых пределах данных. Он предоставляет разработчику удобный интерфейс для оповещения пользователя о допущенных нарушениях и является лучшей заменой простому окну сообщений.
    FolderBrowserDialog Представляет собой диалоговое окно для навигации по папкам файловой системы компьютера.
    FontDialog Является стандартным диалоговоым окном, с помощью которого можно выбирать шрифты, установленные в настоящее время на текущем компьютере.
    GroupBox Применяется для связывания элементов управления в единую группу как дочерних. Используется для наглядности компактного размещения логически связанных элементов и обеспечения их согласованной работы. Перемещение элемента GroupBox в режиме дизайна в пределах формы приводит к одновременному перемещению всех включенных в группу элементов.
    HelpProvider Используется для связывания файлов справки (*.chm, *.htm) с приложением.
    HScrollBar Самостоятельный элемент управления, который присоединяется к другим элементам интерфейса для продвижения по большим массивам информации в горизонтальном направлении.
    ImageList Используется для хранения последовательности рисунков, подлежащих отображению приложением. Рисунки можно выбирать с помощью индексов списка и отображать на экране другими элементами управления.
    Label Простая текстовая метка для отображения нередактируемого текста на экране компьютера.
    LinkLabel Позволяет использовать текстовую метку в стиле гиперссылки. С помощью этого элемента часть текста можно связать с файлом, каталогом или Web-страницей.
    ListBox Отображает список элементов, из которых пользователь может выбрать один или несколько элементов. Если количество элементов в вписке превышает то, что может быть отображено, то автоматически добавляется вертикальная полоса прокрутки. При установке свойства MultiColumn в значение true добавляется горизонтальная полоса прокрутки. Если установлено в true свойство ScrollAlwaysVisible, то полоса прокрутки появляется всегда, независимо от количества элементов. Свойство SelectionMode устанавливает, сколько элементов списка может быть выделено одновременно. Свойство SelectedIndex возвращает индекс первого выделенного элемента в списке, начиная с нуля. Если нет выделенных элементов, свойство возвращает значение -1.
    ListView Отображает список элементов с иконками, наподобие правой области Windows Explorer. Элемент имеет четыре режима отображения: LargeIcon, SmallIcon, List, и Details.
    MenuStrip Создает главное меню формы, за пунктами которого можно закреплять различные команды управления приложением.
    MonthCalendar Обеспечивает привычный интерфейс работы с датой в виде календаря.
    NotifyIcon Используется для отображения в виде значков процессов, которые выполняются в фоновом режиме и долгое время не видны пользователю. Примером может служить программа антивирусной защиты, которую при необходимости пользователь может вызвать щелчком на уведомляющем значке в панели задач.
    NumericUpDown Представляет собой комбинацию текстового поля и пары стрелок, которые пользователь может применять для наглядного управления целым числовым значением.
    OpenFileDialog Представляет стандартное диалоговое окно открытия файла.
    PageSetupDialog Предоставляет стандартное диалоговое окно настройки страницы документа при печати.
    Panel Элемент Panel подобен элементу GroupBox. Применяется для связывания элементов управления в единую группу как дочерних. Используется для наглядности компактного размещения логически связанных элементов и обеспечения их согласованной работы. Имеет собственные полосы прокрутки, но не отображает заголовок.
    PictureBox Элемент служит для отображения рисунков в формате bitmap, GIF, JPEG, metafile, или icon. Отображаемый рисунок определяется свойством Image. Свойство SizeMode устанавливает режим согласования размеров элемента и рисунка. Рисунок отображается как в режиме разработки, так и во время выполнения приложения.
    PrintDialog Это стандартное диалоговое окно используется для настроек принтера перед печатью.
    PrintDocument Устанавливает, что печатать и как печатать. Может использоваться совместно с элементом PrintDialog для полного описания всех аспектов печати.
    PrintPreviewControl Позволяет предварительно просмотреть документ перед печатью, как он будет выглядеть после печати.
    PrintPreviewDialog Позволяет предварительно просмотреть документ перед печатью, как он будет выглядеть после печати. Отображает стандартное диалоговое окно с необходимыми элементами управления.
    ProgressBar Индикаторная линейка - отображает продвижение процесса в горизонтальном направлении.
    RadioButton Радиокнопка (переключатель)
    RichTextBox Представляет собой полноценный текстовый редактор.
    SaveFileDialog Обеспечивает стандартный настраиваемый диалог сохранения файлов.
    Splitter Используется для изменения относительных размеров склеенных элементов управления во время выполнения приложения.
    StatusBar Элемент создает строку состояния.
    TabControl Элемент для создания вкладок. Создает одну или несколько вкладок, на каждой из которых могут быть размещены другие объекты.
    TextBox Редактируемое текстовое поле.
    Timer Таймер
    ToolStrip Панель инструментов - контейнер для кнопок быстрого доступа.
    ToolTip Для создания всплывающих коротких подсказок, которые появляются при наведении курсора на элемент управления.
    TrackBar Регулятор для визуального изменения числовой информации (иногда называют Slider - бегунок).
    TreeView Отображает информацию в древовидном формате.
    VScrollBar Самостоятельный элемент управления, который присоединяется к другим элементам интерфейса для продвижения по большим массивам информации в вертикальном направлении.
    В панели Toolbox имеется возможность добавлять свои вкладки и копировать в них нужный набор инструментов из других вкладок. Добавить вкладку можно, щелкнув правой кнопкой мыши в любом месте панели Toolbox и выполнив команду контекстного меню Add Tab. Удалить вкладку можно, щелкнув правой кнопкой мыши на заголовке соответствующей вкладки и выполнив команду Delete Tab. Копировать нужные компоненты из одной вкладки в другую можно выполнением команд контекстного меню Copy и Paste.

    Упражнение 2. Простой калькулятор

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

  • Добавьте к проекту новую форму командой Project/Add Windows Form и задайте ей имя Calculate
  • Поместите на форму элементы из вкладки Common Controls панели Toolbox в соответствии с таблицей, чтобы пользовательский интерфейс формы был таким
  • Таблица свойств формы Calculate
    Элемент Свойство Значение
    Form Name Calculate
      StartPosition Manual
      Location 0; 0
      Text Простой калькулятор
      Icon Выбрать по усмотрению...(можно из Source)
      FormBorderStyle FixedDialog
    Label Name lblFirst
      Text Первое число:
      TextAlign MiddleRight
    Label Name lblSecond
      Text Второе число:
      TextAlign MiddleRight
    Label Name lblResult
      Text Результат:
      TextAlign MiddleRight
    TextBox Name txtFirst
      Text пусто
    TextBox Name txtSecond
      Text пусто
    TextBox Name txtResult
      Text пусто
      ReadOnly True
      TabStop False
    Button Name btnIncrement
      Text +
      Font/Bold True
      Font/Size 20
      Size 40; 40
    Button Name btnDecrement
      Text -
      Font/Name Courier New
      Font/Bold True
      Font/Size 20
      Size 40; 40
    Button Name btnIncrease
      Text *
      Font/Name Courier New
      Font/Bold True
      Font/Size 20
      Size 40; 40
    Button Name btnDivide
      Text :
      Font/Name Courier New
      Font/Bold True
      Font/Size 20
      Size 40; 40
    Button Name btnExit
      Text Выход

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

    Рекомендуемые префиксы для некоторых элементов управления
    Объект Префикс
    Button btn
    CheckBox chk
    ComboBox cmb
    DataGrid dat
    Form frm
    Label lbl
    ListBox lst
    MenuStrip mnu
    PictureBox pic
    RadioButton rad
    TextBox txt
  • Добавьте к классу Calculate функцию Main() для автономной отладки формы
  • static void Main()
        {
          Application.Run(new Calculate());
        }
  • Выполните команду меню WinFormsApp Properties и для вкладки Application установите в свойстве Startup Object форму Calculate стартовой
  • Защитите интерфейс формы Calculate от случайных изменений, выполнив команду Format/Lock Controls меню оболочки
  • Теперь нужно реализовать функциональность интерфейса. Прежде всего нужно защитить поля ввода от всех символов, кроме цифр, одного знака минус и одной точки. Стрелки и клавиша Del в текстовых полях функционируют, но работу клавиши Backspace нужно учесть явно.

  • Объявите в конце класса Calculate логическое поле isNumeric для отфильтровывания нецифровых символов, которые пользователь может попытаться ввести в текстовые поля
  • private bool isNumber = false;
  • Выделите текстовое поле txtFirst и через панель Properties в режиме Events создайте обработчик для события KeyDown. Заполните обработчик так
  • private bool isNumber = false;
      
        private void txtFirst_KeyDown(object sender, System.Windows.Forms.KeyEventArgs e)
        {
          isNumber = 
            e.KeyCode >= Keys.D0  e.KeyCode <= Keys.D9 // keyboard - основная клавиатура
            || e.KeyCode >= Keys.NumPad0  e.KeyCode <= Keys.NumPad9 // keypad - дополнительная клавиатура
            || e.KeyCode == Keys.Back;
        }
  • Выделите текстовое поле txtFirst и через панель Properties в режиме Events создайте обработчик для события KeyPress. Заполните обработчик так
  • private void txtFirst_KeyPress(object sender, System.Windows.Forms.KeyPressEventArgs e)
        {
          TextBox box = (TextBox) sender;// Явное преобразование типов
      
          switch(e.KeyChar) // Переключатель
          {
            case '-': // Разрешаем минус, если он первый
              if(box.Text.Length == 0)
                isNumber = true;
              break;
            case '.':  
              // Точка не должна быть первой
              if(box.Text.Length == 0)
                break;
              // Точка не должна следовать сразу за минусом
              if(box.Text[0] == '-'  box.Text.Length == 1)
                break;
              // Точка должна быть одна
              if(box.Text.IndexOf('.') == -1)
                isNumber = true; // Еще не было точек
              break;
          }
      
          // Запрещаем в текстовом поле лишние символы
          if(!isNumber)
            e.Handled = true;
        }
  • Выделите текстовое поле txtSecond и через панель Properties в режиме Events подключите к событиям KeyDown и KeyPress соответствующие обработчики, только что созданные для поля txtFirst. Обработчики подключите через раскрывающиеся списки полей значений
  • Здесь мы одни и те же обработчики используем для разных полей, поскольку необходимо выполнять одинаковые действия. Задача одна - не допускать для ввода в поля никакие другие символы, кроме цифр, одного минуса и одной точки. Возможность ввода цифр реализована для основной ( keyboard ) и дополнительной ( keypad ) частей клавиатуры. Параметр sender передает в обработчик ссылку на активное текстовое поле, вызвавшее событие редактирования.

    Конечно, программа будет более понятна, если для каждого элемента создавать свой обработчик. Но очень часто, как в нашем случае, преобладающая часть кода может быть совершенно одинакова в каждом обработчике. Тогда имеет смысл объединять несколько индивидуальных обработчиков в один. Какой подход выбрать - зависит от конкретной задачи и предпочтений программиста.

  • Добавьте в конец класса Calculate объявления числовых переменных, с которыми мы будем производить простые арифметические операции
  • // Объявляем числовые переменные как поля-члены класса
        // Их можно объявить как локальные и внутри обработчика btn_Click()
        // Но оставляем область видимости класс, вдруг где-нибудь еще пригодятся!
        private double numFirst, numSecond, numResult;
  • Перейдите в режим Design формы Calculate и выделите все четыре кнопки с операциями
  • Установите в панели Properties режим Events, найдите событие Click и введите вручную в поле значений этого события имя обработчика btn_Click
  • В созданный оболочкой общий обработчик для всех выделенных кнопок введите следующий код
  • // Один обработчик для всех кнопок-операций
        private void btn_Click(object sender, System.EventArgs e)
        {
          // Копируем текстовые поля в локальные переменные
          string strFirst = string.Copy(txtFirst.Text);
          string strSecond = string.Copy(txtSecond.Text);
      
          // Замена в строке точки символом запятой
          // для корректного преобразования в число
          int pos = strFirst.IndexOf('.');
          if(pos != -1)
          {
            strFirst = strFirst.Substring(0, pos)
              + ','
              + strFirst.Substring(pos + 1);
          }
          pos = strSecond.IndexOf('.');
          if(pos != -1)
          {
            strSecond = strSecond.Substring(0, pos)
              + ','
              + strSecond.Substring(pos + 1);
          }
      
          // Преобразуем текст в число для выполнения операций
          if(txtFirst.Text.Length > 0)
            numFirst = Convert.ToDouble(strFirst);
          else 
            numFirst = 0.0D;
          if(txtSecond.Text.Length > 0)
            numSecond = Convert.ToDouble(strSecond);
          else 
            numSecond = 0.0D;
      
          // Выполняем нужную операцию
          string btnText = "";// Создали строковую переменную
          bool divideFlag = false;// Флаг деления на ноль
          Button btn = (Button) sender;// Явное приведение типов для распознавания кнопок
          switch(btn.Name)// Переключатель
          {
            case "btnIncrement":// Операция сложения
              btnText = "\"+\"";// Экраны кавычек
              numResult = numFirst + numSecond;
              break;
            case "btnDecrement":// Операция вычитания
              btnText = "\"-\"";// Экраны кавычек
              numResult = numFirst - numSecond;
              break;
            case "btnIncrease":// Операция умножения
              btnText = "\"*\"";// Экраны кавычек
              numResult = numFirst * numSecond;
              break;
            case "btnDivide":// Операция деления
              btnText = "\":\"";// Экраны кавычек
              // Проверяем корректность деления
              if (Math.Abs(numSecond) < 1.0E-30)
              {
                MessageBox.Show(
                  "Делить на ноль нельзя!", // Сообщение
                  "Ошибка", // Заголовок окна
                  MessageBoxButtons.OK, // Кнопка OK
                  MessageBoxIcon.Stop);// Критическая иконка
                divideFlag = true;
              }
              else
                numResult = numFirst / numSecond;
              break;
          }
      
          // Для отображения в панели Output режима Debug
          System.Diagnostics.Debug.WriteLine("Нажата кнопка " + btnText);// Конкатенация
      
          // Отображение результата
          if(!divideFlag)
          {
            txtResult.Text = Convert.ToString(numResult);
            this.Validate(); // Обновить экран (можно убрать-излишне)
          }
        }

    Здесь мы прежде всего скопировали значения полей ввода в промежуточные текстовые переменные, используя статический метод System.String. Copy() класса String (псевдоним string ). Затем мы проверяем наличие символа "точки" в этих переменных и при обнаружении производим замену на символ "запятая" с полным формированием новой строки. Мы не можем заменить символ "на месте" в существующей строке, обратившись к нему как элементу массива, поскольку индексная форма адресации в строках существует только для чтения.

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

    Далее мы явно приводим переданную в обработчик ссылку типа object на нажатую кнопку к типу Button. В заголовке переключателя выделяем имя нажатой кнопки и выполняем соответствующую арифметическую операцию. Перед выполнением последней операции мы проверяем возможность возникновения случая " деления на ноль " и при его обнаружении предупреждаем пользователя выводом простого диалогового окна сообщений, отменяя саму операцию деления.

    После переключателя мы располагаем оператор вывода строки System.Diagnostics.Debug.WriteLine() с выполненной операцией в панель оболочки Output. Этот класс предназначен для работы с программой в отладочном режиме Debug и автоматически изымается из кода при компиляции окончательного варианта приложения в режиме Release.

    На последнем этапе, в коде обработчика, мы выводим результат в соответствующее текстовое поле с предварительным преобразованием типов. Затем мы даем команду системе обновить окно приложения, хотя в данном случае эта мера является излишней - система и так обновляет результат в текстовом поле.

    Теперь создадим обработчик нажатия на кнопку закрытия формы.

  • В режиме Design двойным щелчком на кнопке btnExit создайте обработчик, который заполните так
  • private void btnExit_Click(object sender, System.EventArgs e)
        {
          this.Close();
        }
  • Запустите проект и проверьте функциональность простого калькулятора
  • Теперь мы должны подключить разработанную форму калькулятора к основному окну приложения.

  • Установите в качестве стартовой форму Start. Для этого выполните команду меню оболочки Project/WinFormsApp Properties и в появившемся диалоговом окне установите для вкладки Application свойство Startup Object в значение WinFormsApp.Program
  • Откройте файл Start.cs в режиме View Code. Через раскрывающийся список Members в верхней части окна редактора кода найдите обработчик события generalList_SelectedIndexChanged(), который мы создали ранее, и дополните его вызовом окна калькулятора
  • private void generalList_SelectedIndexChanged(object sender, System.EventArgs e)
        {
          switch(generalList.SelectedIndex + 1)
          {
            case 1:
              Smiles  frm1 = new Smiles();
              frm1.ShowDialog();
              break;  
            case 2:
              Calculate frm2 = new Calculate();
              frm2.ShowDialog();
              break;
          }
        }
  • В панели Solution Explorer оболочки щелкните дважды на пиктограмме файла Start.cs, чтобы открыть его в режиме View Designer, выделите элемент списка в клиентской области формы и через панель Properties добавьте в свойство Items строку " 2) Простой калькулятор "
  • Запустите приложение и проверьте его работоспособность
  • Применение коллекций для предотвращения повторных запусков формы

    В C# под коллекцией понимается группа объектов, возможно, не одинаковых типов. Самым простым примером коллекции является обычный массив. Но в отличие от массива коллекции способны хранить объекты разных типов. Коллекции реализованы в виде классов, сгруппированных в пространстве имен System.Collections библиотеки mscorlib.dll

    C# - классы коллекций по сути аналогичны классам стандартной библиотеки шаблонов ( STL - Standard Template Library), определенной в C++. То, что в C++ называется контейнером, в C# именуется коллекцией. Коллекции упрощают программирование, предлагая уже готовые решения для построения структур данных, разработка которых "с нуля" потребовала бы больших затрат.

    Основное достоинство коллекций состоит в том, что они упрощают работу с группами объектов в прикладных программах. Все коллекции разработаны на основе набора четко определенных интерфейсов ( ICollection, IComparer, IDictionary и т.д.).

    Для контроля за запуском форм упражнений и предотвращения их повторного запуска можно использовать обычный массив, куда при каждом запуске очередной формы сохранять метку на форму и при повторной попытке проверять существование этой метки. Но недостатком использования массива является его фиксированный размер, определяемый однажды при создании массива. Коллекцию использовать удобнее, поскольку механизм автоматического изменения размера в нее уже встроен, и предусмотрен ряд полезных методов для управления коллекцией. Все коллекции предполагают использование цикла foreach (в каждом) для последовательного перебора всех элементов, входящих в коллекцию.

    Мы будем использовать класс ArrayList, представляющий собой массив переменной длины ( динамический массив ), элементами которого являются объектные ссылки. Только, для удобства и тренировки мы упакуем этот класс в свой класс, в котором предусмотрим необходимые нам методы и свойства. При этом мы не будем создавать для нового класса отдельный файл, а добавим его в файл Start.cs. Все методы класса и ссылку на коллекцию сделаем статическими, чтобы не создавать экземпляр класса в основном коде программы.

  • Добавьте в конец файла Start.cs после класса Start следующий код
  • // Класс для предотвращения повторных запусков форм
      public class Restart
      {
        // Создали коллекцию
        private static System.Collections.ArrayList frmList = 
          new System.Collections.ArrayList();
      
        // Метод для добавления метки в коллекцию
        public static void Add(Object frm)
        {
          frmList.Add(frm);
        }
      
        // Метод для удаления метки из коллекции
        public static void Remove(String str)
        {
          frmList.Remove(str);
        }
      
        // Метод, который отвечает на вопрос - запущена ли форма
        public static bool IsPresent(Object frm)
        {
          bool flag = false;
          foreach(Object x in frmList)
          {
            if(Object.Equals(x.ToString(), frm.ToString())) 
              flag = true;
          }
          return flag;
        }
      }
  • Найдите в файле Start.cs обработчик generalList_SelectedIndexChanged() и замените его тело на следующий код
  • private void generalList_SelectedIndexChanged(object sender, System.EventArgs e)
        {
          switch(generalList.SelectedIndex + 1)
          {
            case 1:
              Smiles frm1 = new Smiles();
              if(!Restart.IsPresent(frm1))
              {
                Restart.Add(frm1);
                frm1.Show();
              }
              break;  
            case 2:
              Calculate frm2 = new Calculate();
              if(!Restart.IsPresent(frm2))
              {
                Restart.Add(frm2);
                frm2.Show();
              }
              break;
          }
        }
  • В режиме дизайна форм Smiles и Calculate создайте обработчики для события FormClosed, которые заполните кодом удаления метки из коллекции при закрытии формы
  • private void Smiles_FormClosed(object sender, FormClosedEventArgs e)
            {
                Restart.Remove(this.ToString());
            }
    private void Calculate_FormClosed(object sender, FormClosedEventArgs e)
            {
                Restart.Remove(this.ToString());
            }
  • Запустите приложение и проверьте, что повторный запуск уже запущенной дочерней формы блокируется
  • В реализациях следующих упражнений этой лабораторной работы нам необходимо соблюдать введенную нами технологию предотвращения повторных запусков дочерних форм. Для этого в переключателе switch обработчика generalList_SelectedIndexChanged() нужно добавлять метку запущенной формы в коллекцию нашего класса Restart, а при закрытии дочерней формы необходимо удалять эту метку из коллекции в обработчике события FormClosed.

    Упражнение 3. Встраивание COM-объекта "Windows Media Player" в свое приложение

    В этом упражнении мы встроим мультимедиа - проигрыватель в наше приложение и создадим пользовательские элементы для управления им. Прежде всего нужно добавить этот COM -объект ( COM - Component Object Model - объектная модель компонентов) к панели инструментов Toolbox оболочки.

    Добавление своей вкладки в панель Toolbox оболочки

    Чтобы не смешивать набор элементов стандартных вкладок панели Toolbox, поместим этот элемент в отдельную вкладку.

    В панели Toolbox имеется возможность добавлять свои вкладки и копировать в них нужный набор инструментов из других вкладок. Добавить вкладку можно, щелкнув правой кнопкой мыши в любом месте панели Toolbox и выполнив команду контекстного меню Add Tab. Удалить вкладку можно, щелкнув правой кнопкой мыши на заголовке соответствующей вкладки и выполнив команду Delete Tab. Копировать нужные компоненты из одной вкладки в другую можно выполнением команд контекстного меню Copy и Paste.
  • Через панель Solution Explorer откройте любой файл проекта в режиме дизайна, чтобы стала доступна панель инструментов Toolbox. Щелкните правой кнопкой мыши на любом месте панели Toolbox и через контекстное меню выполните команду Add Tab
  • Присвойте добавленной вкладке имя " Моя вкладка " и раскройте ее
  • Присоединение COM-объекта к проекту

    Прежде всего нужно проследить за тем, чтобы перед функцией Main() в файле Start.cs стоял атрибут [STAThread], который сообщает среде исполнения, что основной программный поток приложения должен использовать однопоточную модель. Это необходимо для правильного взаимодействия с подсистемой COM.
  • Щелкните на новой вкладке правой кнопкой мыши и выполните команду контекстного меню Choose Items
  • В появившемся окне выберите вкладку COM Components, найдите в списке Windows Media Player, отметьте его и щелкните на кнопке OK
  • После этого в новой вкладке панели Toolbox появится пиктограмма выбранного компонента

    и его можно размещать на форме обычным образом.

    Замечание. Возможно, что оболочка на Вашем компьютере по умолчанию настроена на другой тип COM -компонента, который будет иметь другие свойства и события, чем используемый в этой работе. В этом случае щелкните на кнопке Browse вкладки COM Components окна выбора элементов Choose Toolboxs Items и в системном каталоге Windows/System32 выберите компонент msdxm.ocx. Это и будет интересующий нас компонент мультимедиа - проигрывателя.

    Добавление к приложению новой формы и ее разработка

  • Через меню оболочки выполните команду Project/Add Windows Form , чтобы добавить к проекту новую форму, и в появившемся диалоговом окне задайте имя файла формы MediaPlayer.cs
  • Визуальное создание и настройка COM-объекта

  • Поместите на форму с вкладки " Моя вкладка " компонент плеера. Форма после этого будет иметь такой вид
  • Выделите компонент видеоплейера на форме и через панель Properties задайте ему следующие свойства
  • Установка свойств компонента Windows Media Player
    Свойство Значение Пояснения
    Name Player Имя компонента
    AutoRewind True Автоперемотка, чтобы после просмотра видеоплеер устанавливался в начало
    AutoStart False Чтобы плеер не начинал проигрывать файл сразу после его открытия, а ждал отдельной команды на проигрывание
    ClickToPlay False Отключили возможность проигрывания/остановки по щелчку на самом плеере
    Size/Width 286 Можно настроить в визуальном режиме
    Size/Height 280 Можно настроить в визуальном режиме
  • Перейдите в режим редактирования кода файла MediaPlayer.cs и добавьте в конец класса MediaPlayer точку входа для автономного запуска вместе с атрибутом однопоточности [STAThread]
  • // Точка входа
        [STAThread]    
        static void Main()
        {
          Application.Run(new MediaPlayer());
        }
  • Выполните команду меню Project/WinFormsApp Properties и установите в свойстве Startup Object значение WinFormsApp.MediaPlayer, чтобы сделать форму плеера стартовой на период отладки
  • Если выделить компонент плеера и посмотреть его свойства в панели Properties, то можно увидеть много возможностей для его начальной настройки в режиме дизайна. Вот некоторые из свойств

    Некоторые свойства компонента плеера
    Свойство Пояснение
    Rate Темп воспроизведения. Если установить его значение, например, равным 2, то файл будет проигрываться в удвоенном темпе
    PlayCount Сколько раз повторять проигрывание файла. При значении 0 воспроизведение файла будет повторяться бесконечно
    FileName Файл для проигрывания
    Mute (немой) Начальное состояние кнопки включения звука
    ShowControls Показывать или нет встроенную панель управления плеером
    ShowTracker (буксир) Показывать или нет ползунок поиска проигрывателя
    ShowAudioControls Показывать или нет элементы управления динамиком
    ShowDisplay Показывать или нет информационную панель со сведениями о проигрываемом файле
    ShowPosicionControls Отключает панель управления позицией головки проигрывателя
    CurrentPosition Содержит значение, на какой секунде находится в данный момент воспроизведение файла
    Volume Громкость звука. Число 0 - самый громкий звук. Отрицательное число -10000 означает полную тишину
    Duration Свойство только для чтения, доступно программно. Содержит общую продолжительность проигрываемого файла в секундах

    Часть из этих свойств можно настроить через окно свойств самого компонента, если щелкнуть на нем правой кнопкой мыши. Это окно устанавливает те же самые свойства через более понятный интерфейс

    Добавление собственных элементов управления плеером

    Продублируем встроенные элементы управления плеером своими. Эти действия будем выполнять последовательно шаг за шагом, сразу программируя и проверяя их работу.

  • Увеличьте вниз размер формы так, чтобы освободить место для элементов управления. Разместите на форме из вкладки Containers панели Toolbox элемент управления GroupBox, который будет служить контейнером для наших элементов. Задайте ему свойства: Name = groupBox, Dock =Bottom, Text =" Мои элементы управления "
  • Поместите в верхней части контейнера groupBox четыре кнопки Button. Кнопки помещайте так: щелкайте на компоненте Button вкладки Common Controls панели Toolbox один раз, затем щелкайте внутри контейнера groupBox. Контейнер для кнопок будет родителем и может передавать им значения своих свойств, например, местоположение, цвет
  • Выровняйте кнопки, используя панель инструментов Layout оболочки
  • Замкните элементы управления групповой командой Format/Lock Controls, чтобы случайно не нарушить дизайн
  • Задайте кнопкам следующие свойства
  • Свойства кнопок нашей панели управления
    Элемент Свойство Значение Пояснения
    Button Name btnOpen Кнопка для открытия диалога выбора проигрываемого файла
    Text Open  
    Button Name btnPlay Кнопка для начала воспроизведения
    Text Play  
    Button Name btnStop Кнопка для остановки воспроизведения
    Text Stop  
    Button Name btnRewind Кнопка установки в начало воспроизведения
    Text Rewind  

    Теперь нужно запрограммировать наши кнопки в соответствии с решаемой задачей.

    Программирование кнопок

    Кнопка btnOpen должна загружать файл, предназначенный для проигрывания. Воспользуемся стандартным диалогом открытия файла, предусмотренным в библиотеке FCL.

  • Поместите из вкладки Dialogs панели Toolbox компонент OpenFileDialog. Это невизуальный компонент (неотображаемый на форме на этапе проектирования, а размещаемый в подвале окна редактирования оболочки), поэтому его экземпляр можно создать двойным щелчком на пиктограмме компонента
  • Настройте объект диалога открытия файла в соответствии с таблицей через панель Properties, предварительно выделив его в подвале графического редактора
  • Свойства экземпляра класса OpenFileDialog организации стандартного диалога
    Элемент Свойство   Значение
    OpenFileDialog Name   openFilePlayer
    Filter
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    Wave (Microsoft) (*.wav) |*.wav| 
    Dialogic VOX ADPCM (*.vox) |*.vox| 
    InterVoice (*.ivc) |*.ivc| 
    Macintosh AIFF (*.aif,*.aiff,*.snd) |*.aif,*.aiff,*.snd| 
    MP3 Audio (*.mp3) |*.mp3| 
    NeXT/Sun (Java) File (*.ai,*.snd) |*.ai,*.snd| 
    OggVorbis (*.ogg) |*.ogg|
    Perfect Clarity Audio (*.pca) |*.pca|
    QuickTime (*.mov) |*.mov|
    Raw File (*.raw) |*.raw|
    RealMedia (*.rm) |*.rm|
    Sound Designer 1 (*.dig,*.sd) |*.dig,*.sd|
    Video for Windows (*.avi) |*.avi|
    Windows Media (*asf) |*asf|
    Windows Media Audio (*.wma) |*.wma|
    Windows Media Video (*.wmv) |*.wmv|
    All Files (*.*) |*.*
    FilterIndex   13

    Свойство Filter предназначено для управления пользователем типом отображаемых файлов, а свойство FilterIndex устанавливает, какой фильтр появится первым при запуске окна. Фильтры в свойстве Filter следуют парами друг за другом " Название фильтра|шаблон_фильтра " и разделяются символом "Вертикальная черта".

    Внимание!!! Если вы будете копировать значение свойства Filter прямо из этой таблицы, то предварительно нужно убрать все невидимые символы перевода на новую строку (например, в блокноте), которые здесь введены в целях форматирования. Строка фильтра должна быть непрерывной. В шаблонах_фильтране должно быть пробелов ни внутри, ни в окружении, иначе фильтр не сработает.

    Создадим, как и в случае с калькулятором, один обработчик для всех размещенных ранее кнопок. Для этого выполните следующее...

  • Перейдите в режим дизайна для файла MediaPlayer.cs, выделите первую кнопку btnOpen и через панель Properties для события Click в поле его значений установите вручную имя обработчика btnClick
  • Разместите в созданном оболочкой обработчике следующий код
  • private void btnClick(object sender, System.EventArgs e)
        {
          Button btn = (Button) sender;// Явное приведение типов
          switch(btn.Name)
          {
            case "btnOpen":
              openFilePlayer.InitialDirectory = // Начальный каталог для фильтра
                System.IO.Directory.GetCurrentDirectory();// Каталог исполнимого файла
              openFilePlayer.ShowDialog();// Открываем диалог
              Player.FileName = openFilePlayer.FileName;// Передаем имя файла в плеер
              break;
          }
        }
  • Подсоедините обработчик btnClick к остальным кнопкам. Для этого откройте панель Properties в режиме Events, выделите оставшиеся три кнопки вместе и через раскрывающийся список в поле значения свойства Click выберите обработчик btnClick
  • Дополните код обработчика btnClick так
  • private void btnClick(object sender, System.EventArgs e)
        {
          Button btn = (Button) sender;// Явное приведение типов
          switch(btn.Name)
          {
            case "btnOpen":
              openFilePlayer.InitialDirectory = // Начальный каталог для фильтра
                System.IO.Directory.GetCurrentDirectory();// Каталог исполнимого файла
              openFilePlayer.ShowDialog();// Открываем диалог
              Player.FileName = openFilePlayer.FileName;// Передаем имя файла в плеер
              break;
            case "btnPlay":
              Player.Play();
              break;
            case "btnStop":
              Player.Stop();
              break;
            case "btnRewind":
              Player.CurrentPosition = 0;
              break;
          }
        }

    После завершения работы стандартного диалогового окна OpenFileDialog его свойство FileName либо содержит полное (вместе с путем) имя выбранного файла, либо пустую строку, если пользователь отказался от выбора.

    Теперь мы готовы к испытанию формы. Запустите приложение и загрузите какой-нибудь звуковой- или видео файл (например, прилагаемый к данной работе в каталоге Source файл " WellWait - 02.AVI "). Поэкспериментируйте с кнопками - они все работают.

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

  • Использовать операторы обработки исключений try...catch
  • Блокировать кнопку btnPlay до тех пор, пока не будет загружен файл для проигрывания
  • Мы воспользуемся вторым способом. Для начального блокирования кнопки есть три пути:

  • Установить свойство Enabled кнопки на этапе проектирования в состояние False
  • Программно установить свойство Enabled кнопки в состояние false в конструкторе класса MediaPlayer
  • Создать для формы обработчик события Load и разместить в нем код установки кнопки в недоступное состояние
  • Мы воспользуемся последним способом. При этом будем блокировать все кнопки, кроме btnOpen, чтобы лишний раз не вводить в заблуждение нашего дорогого пользователя.

  • Перейдите в режим View Designer формы, выделите форму щелчком на ее заголовке или через раскрывающийся список панели Properties, установите панель Properties в режим Events и создайте обработчик события Load формы двойным щелчком на поле значений этого события. Заполните обработчик следующим кодом
  • private void MediaPlayer_Load(object sender, System.EventArgs e)
        {
          btnPlay.Enabled = btnStop.Enabled = btnRewind.Enabled = false;
        }

    Здесь мы употребили сцепленную операцию присваивания.

    Теперь нужно разблокировать кнопки после того, как будет загружен файл в проигрыватель. Для этого

  • Дополните обработчик btnClick следующим кодом
  • private void btnClick(object sender, System.EventArgs e)
        {
          Button btn = (Button) sender;// Явное приведение типов
          switch(btn.Name)
          {
            case "btnOpen":
              openFilePlayer.InitialDirectory = // Начальный каталог для фильтра
                System.IO.Directory.GetCurrentDirectory();// Каталог исполнимого файла
              openFilePlayer.ShowDialog();// Открываем диалог
              Player.FileName = openFilePlayer.FileName;// Передаем имя файла в плеер
              if(Player.FileName.Length > 0)
              {
                // Перебираем все дочерние элементы контейнера GroupBox
                foreach(Control obj in groupBox.Controls)
                {
                  // Выделяем полное имя типа вместе с пространствами имен
                  String str = obj.GetType().ToString();
                  // Ищем позицию последней точки
                  int pos = str.LastIndexOf('.');
                  // Выделяем имя типа без пути
                  str = str.Substring(pos + 1);
                  if(str == "Button")
                    obj.Enabled = true;
                }
              }
              break;
            case "btnPlay":
              Player.Play();
              break;
            case "btnStop":
              Player.Stop();
              break;
            case "btnRewind":
              Player.CurrentPosition = 0;
              break;
          }
        }

    В добавленном коде мы проверяем, что выбранное пользователем имя файла непустое (надо было все-таки поставить обработчик исключения, поскольку пользователь может выбрать файл, не подлежащий проигрыванию. Но пока хватит и этого!).

    Родительские элементы, такие как Panel, GroupBox, TabControl, сама форма Form, имеют свойство Controls, которое является коллекцией и содержит ссылки на все помещенные на родительский элемент дочерние компоненты - наследники класса Control.

    Мы перебираем в цикле foreach ( -для каждого ) все элементы коллекции GroupBox, находим среди них кнопки и устанавливаем их доступными. Здесь мы наворотили лишние проверки на тот случай, если кроме кнопок в контейнере GroupBox окажутся и элементы других типов, хотя на данном этапе кроме кнопок мы туда ничего не помещали.

  • Запустите проект и убедитесь, что все добавленные нами возможности управления работают правильно.
  • Добавление к форме других элементов управления

    Усовершенствуем схему управления медиаплеером. Задействуем возможности управления звуком и контроля позиции проигрывающей головки. Для этого нам понадобятся такие элементы управления вкладки All Widows Forms, как TrackBar ( ползунок ), CheckBox ( флажок ), ProgressBar ( индикатор процесса, индикатор прогресса ), TextBox ( текстовое поле ).

  • Сместите кнопку btnRewind влево на один уровень с кнопкой btnOpen и поместите на освободившееся справа место элемент CheckBox (один щелчок на CheckBox, затем щелчок внутри контейнера groupBox ). Этот элемент даст возможность пользователю отключать или включать звук при воспроизведении файла
  • Правее элемента CheckBox разместите в контейнере groupBox текстовое поле TextBox, которое мы будем использовать для отображения численного значения величины звука
  • Ниже разместите в контейнере groupBox элемент TrackBar для плавного регулирования звука
  • Теперь нужно настроить эти элементы управления. Начнем с элемента CheckBox. Этот элемент мы будем использовать для отключения звука плеера. Настройте его свойства так

    Свойства элемента CheckBox для отключения звука
    Свойство Значение
    Name checkVolume
    CheckAlign MiddleLeft
    Image VOLUME01.ICO (возьмите из данной работы в каталоге Source. Используйте кнопку Import для радиокнопки Local resource )
    ImageAlign BottomRight
    Checked True
    Text ПУСТО

    Давайте сразу запрограммируем этот элемент. При каждом щелчке на элементе CheckBox изменяется его булево свойство CheckedCheckState ).

  • Создайте в панели Properties обработчик события CheckedChanged элемента checkVolume и добавьте в него следующий код
  • private void checkVolume_CheckedChanged(object sender, System.EventArgs e)
        {
          // Это наше извращение, можно сразу обращаться к checkVolume
          CheckBox check = (CheckBox) sender;
      
          // В каком состоянии оказался CheckBox
          if(check.CheckState == CheckState.Checked)
          {
            Player.Mute = false;
          }
          else
          {
            Player.Mute = true;
          }
        }

    Для плавного изменения звука мы воспользуемся элементом TrackBar. Свойства и методы элемента TrackBar аналогичны полосам прокрутки ScrollBar. Некоторые из них перечислены в таблице. Причем не все свойства элемента TrackBar доступны в режиме проектирования, зато все доступны в программном режиме на этапе выполнения.

    Некоторые свойства элемента TrackBar, доступные в режиме View Designer
    Свойство Пояснения
    Value Главная регулируемая величина, определяющая текущее состояние головки бегунка. По умолчанию начальное значение равно значению свойства Minimum
    SmallChange Минимальная дискретность изменения величины Value при управлении стрелками или перемещением головки бегунка с захватом мышью. По умолчанию установлено 1
    LargeChange Максимальная дискретность изменения величины Value при нажатии клавиш PageUp или PageDown, или щелчках мышью на шкале элемента. По умолчанию установлено 5
    Minimum Нижний предел значения Value. По умолчанию 0
    Maximum Верхний предел значения Value. По умолчанию 10
    TickFrequency Свойство целого типа, определяющее частоту делений на шкале ползунка. Расчитывается с использованием значений свойств Minimum и Maximum
    TickStyle Определяет форму ползунка при отображении пользователю
  • Настройте свойства элемента TrackBar так
  • Свойства элемента TrackBar для регулирования величины звука
    Свойство Значение
    Name trackVolume
    Location 8; 104
    Size 272; 53
    Minimum 0
    Maximum 50
    Orientation Horizontal
    LargeChange 5
    SmallChange 1
    TickFrequency 5
    TickStyle BottomRight
  • Присвойте элементу TextBox имя txtVolume
  • Элемент txtVolume будет только отображать числовое значение Volume плеера, поэтому запретим его редактирование пользователем.

  • Выделите элемент txtVolume и создайте через панель Properties для его события KeyPress обработчик, который заполните так
  • private void txtVolume_KeyPress(object sender, System.Windows.Forms.KeyPressEventArgs e)
        {
          // Запрещаем редактировать поле, кроме клавиши Del
          // и горизонтальных стрелок - они встроены в элемент
          e.Handled = true;
        }

    Свойство Handled сообщает элементу, что все уже обработано и нужно успокоиться и ничего не делать. Элемент TrackBar имеет событие Scroll, которое происходит каждый раз, когда изменяется положение головки бегунка. Воспользуемся этим, чтобы менять численное значение величины Volume плеера.

  • Создайте для события Scroll элемента TrackBar обработчик, который заполните так
  • private const int maxVolume = 0;
        private const int minVolume = -5000;
        private void trackVolume_Scroll(object sender, System.EventArgs e)
        {
          TrackBar track = (TrackBar) sender;
          float minValue = track.Minimum;
          float maxValue = track.Maximum;
          float value = track.Value;
          // Формула линейного изменения свойства  Player.Volume
          // (самая простая, хотя можно вставить и нелинейный закон)
          Player.Volume = minVolume - 
            (int) ( (value - minValue) /(maxValue - minValue) 
                    * minVolume );
          txtVolume.Text = Convert.ToString(Player.Volume);
        }

    Теперь нужно установить начальные значения текстового поля и положения бегунка при первой загрузке формы

  • Добавьте в обработчик события Load формы, который мы уже создали раньше, следующий код
  • private void MediaPlayer_Load(object sender, System.EventArgs e)
        {
          btnPlay.Enabled = btnStop.Enabled = btnRewind.Enabled = false;
          txtVolume.Text = Convert.ToString(Player.Volume);// Отображаем величину звука
          trackVolume.Value = // Устанавливаем бегунок
            // Поскольку работаем с целыми, которые округляются,
            // то вначале умножаем, потом делим
            trackVolume.Minimum + (minVolume - Player.Volume)
            * (trackVolume.Maximum - trackVolume.Minimum) 
            / minVolume;
        }

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

  • Добавьте в обработчик checkVolume_CheckedChanged() следующий код блокирования ползунка
  • private void checkVolume_CheckedChanged(object sender, System.EventArgs e)
        {
          // Это наше извращение, можно сразу обращаться к checkVolume
          CheckBox check = (CheckBox) sender;
      
          // В каком состоянии оказался CheckBox
          if(check.CheckState == CheckState.Checked)
          {
            Player.Mute = false;
            trackVolume.Enabled = true;
          }
          else
          {
            Player.Mute = true;
            trackVolume.Enabled = false;
          }
        }

    Теперь мы хотим сделать так, чтобы пользователь мог видеть по нашему интерфейсу, какая часть файла уже воспроизведена. Для этого используем индикатор прогресса (процесса) ProgressBar.

    Есть еще альтернативный вариант - COM-индикатор Microsoft ProgressBar Control 6.0 (SP4). Этот индикатор можно загрузить на панель Toolbox точно также, как мы это делали для плеера.

    Откройте вкладку панели Toolbox "Моя вкладка", которую мы создали ранее, щелкните на ней правой кнопкой мыши и выполните команду Coose Items. Установите в появившемся окне вкладку COM Components, найдите нужный элемент Microsoft ProgressBar Control 6.0 (SP4), отметьте его и нажмите кнопку OK. Теперь этот компонент можно помещать на форму обычным образом.

    Некоторые свойства:

  • Scrolling - гладкий или прерывистый вид полосы
  • Min, Max - пределы изменения полосы
  • Value - текущее значение
  • Orientation - горизонтальное или вертикальное расположение полосы
  • Appearance, BorderStyle - внешний вид полосы
  • Поместите компонент ProgressBar в контейнер groupBox (щелчком там и там) и настройте через панель Properties его свойства так
  • Свойства элемента ProgressBar
    Свойство Значение
    Name progressBar
    Location 16; 160
    Size 256; 8

    Здесь мы установили только интерфейсные свойства элемента, а существенные свойства по управлению элементом будем задавать программно.

  • Выровняйте интерфейсные элементы с применением панели инструментов Layout оболочки, чтобы панель имела на данном этапе примерно такой вид
  • Выделите элемент Player и на панели Properties в режиме Events найдите событие ReadyStateChange. Создайте двойным щелчком на поле значений этого события обработчик Player_ReadyStateChange(), который заполните так
  • private void Player_ReadyStateChange(object sender, AxMediaPlayer._MediaPlayerEvents_ReadyStateChangeEvent e)
        {
          progressBar.Minimum = 0;
          int maximum = progressBar.Maximum = (int)Player.Duration;
        }

    Этот обработчик будет срабатывать каждый раз при загрузке нового файла и устанавливать новые значения свойств диапазона индикатора прогресса в секундах.

  • Вновь выделите элемент Player и на панели Properties в режиме Events найдите событие PositionChange. Создайте двойным щелчком на поле значений этого события обработчик Player_PositionChange(), который заполните так
  • private void Player_PositionChange(object sender, AxMediaPlayer._MediaPlayerEvents_PositionChangeEvent e)
        {
          progressBar.Value = (int)Player.CurrentPosition;
        }

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

  • Добавьте двойным щелчком во вкладке All Windows Forms на компоненте Timer таймер к нашей форме и назначьте ему имя timer
  • Создайте для его единственного события Tick обработчик, в котором продублируйте код обработчика Player_PositionChange(), обновляющий позицию элемента progressBar
  • private void timer_Tick(object sender, System.EventArgs e)
        {
          progressBar.Value = (int)Player.CurrentPosition;
    //      progressBar.PerformStep();// Для альтернативного способа
        }
  • Дополните обработчик Player_ReadyStateChange() события загруки медиафайла кодом настройки и запуска таймера
  • private int  countSteps;
        private void Player_ReadyStateChange(object sender, AxMediaPlayer._MediaPlayerEvents_ReadyStateChangeEvent e)
        {
          countSteps = 50; // Количество шагов индикатора прогресса
          progressBar.Minimum = 0;
          progressBar.Maximum = (int)Player.Duration;
          timer.Interval = (progressBar.Maximum - progressBar.Minimum) 
            * 1000 // Переводим секунды в миллисекунды
            / countSteps; // Операция деления на последнем месте
          timer.Start();
          progressBar.Value = progressBar.Minimum;
    /*      // Для альтернативного способа
          progressBar.Step = (progressBar.Maximum - progressBar.Minimum) 
            / countSteps;
    */        
        }

    Красным цветом выделен альтернативный код управления интикатором. Но если вы его будете использовать, то нужно позаботиться об остановке таймера при каждой остановке проигрывания и о его запуске при продолжении проигравания. Если этого не сделать, то при остановке проигрывания индикатор будет продолжать показывать процесс, поскольку таймер не будет остановлен.

  • Выделите форму через ее заголовок и установите два свойства в следующие значения
  • FormBorderStyle=FixedSingle
  • MaximizeBox=False
  • Теперь осталось подключить эту форму к основному окну приложения и сделать необходимые настройки.

  • Создайте обработчик события FormClosed формы MediaPlayer, как мы это делали в предыдущих случаях данной работы для предотвращения повторного запуска, и заполните его так
  • private void MediaPlayer_FormClosed(object sender, System.EventArgs e)
        {
          Restart.Remove(this.ToString());
        }
  • Измените заголовок формы, задав ее свойству Text значение " Упражнение №3 - MediaPlayer "
  • Через панель Solution Explorer откройте файл Start.cs в режиме кода и добавьте к обработчику generalList_SelectedIndexChanged() следующий код
  • private void generalList_SelectedIndexChanged(object sender, System.EventArgs e)
        {
          switch(generalList.SelectedIndex + 1)
          {
          .................................................
            case 3:
              MediaPlayer frm3 = new MediaPlayer();
              if(!Restart.IsPresent(frm3))
              {
                Restart.Add(frm3);
                frm3.Show();
              }
              break;
          }
        }
  • Через панель Solution Explorer откройте файл Start.cs в режиме дизайна двойным щелчком на пиктограмме. Выделите через панель Properties список generalList и добавьте в его свойство Items следующую строку

    3) Собственный Windows Media Player

  • Командой меню оболочки Project/WinFormsApp Properties выберите вкладку Application и верните свойство Startup Object в значение WinFormsApp.Program
  • Запустите приложение, загрузите медиафайл, испытайте элементы управления и полюбуйтесь на свою работу. Просмотрите мультик, прилагаемый к работе
  • Страницы:

    Файлы к лабораторной работе Вы можете скачать здесь.

    В данной лабораторной работе мы рассмотрим некоторые возможности интегрированной среды разработки программного обеспечения ( IDE - Integrated Development Environment ) Visual Studio.NET 2005. Мы будем использовать разработанный корпорацией Microsoft самый красивый и современный язык программирования C# (Си-шарп). Мы будем опираться на мощную библиотеку классов .NET Framework ( FCL - Framework Class Library, она же BCL - Basic Class Library).

    Создание заготовки приложения

  • Выполните команду File/New/Project оболочки для создания нового проекта
  • В диалоговом окне New Project выберите кнопкой Browse папку для размещения проекта, задайте тип, шаблон и имя проекта WinFormsApp
  • После щелчка на кнопке OK мастер создаст заготовку приложения и выведет в режиме дизайна пустую форму, которая при запуске приложения будет представлять окно. Стандартный размер сгенерированной формы равен 300x300. Сделаем эту форму стартовой и разместим на ней элементы управления для вызова дочерних форм, реализующих отдельные упражнения данной работы.

  • Откройте панель Solution Explorer оболочки и переименуйте файл Form1.cs в файл Start.cs
  • Щелкните на форме правой кнопкой мыши и выполните команду контекстного меню View Em, чтобы вызвать представление файла Start.cs в режиме редактора кода
  • В режиме кода вызовите комбинацией клавиш Ctrl-F окно Find and Replace для замены всех вхождений Form1 на Start. После заполнения полей поиска и замены щелкните на кнопке Replace All
  • В раскрывающемся списке Members выделите функцию InitializeComponent(), чтобы быстро позиционироваться в соответствующее место кода
  • Отредактируйте в функции InitializeComponent() код установки заголовка окна в режиме выполнения
  • private void InitializeComponent()
        {
                this.components = new System.ComponentModel.Container();
                this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
                this.Text = "Lab38 - Снетков";
        }

    Установка пароля на главное окно приложения

    Теперь давайте добавим к главной форме Start код поддержки пароля при запуске приложения. Для этого нам потребуется диалоговое окно с текстовым полем. Сконструируем его. Создание диалогового окна будет состоять из трех шагов:

  • Создание самой формы диалогового окна (класс InputPassword )
  • Размещение на форме интерфейсных элементов пользователя
  • Создание кода, управляющего диалоговым окном
  • В панели Solution Explorer выделите корневой узел проекта и командой Add/Windows Form добавьте в проект файл формы с именем InputPassword.cs
  • Удалите из узла References лишние добавленные мастером ссылки на библиотечные сборки System.Data и System.Xml
  • Откройте файл InputPassword.cs в режиме View Code и удалите инструкции using подключения пространств имен System.Data и System.Xml
  • Настройте форму InputPassword в соответствии с таблицей
  • Таблица свойств формы InputPassword
    Свойство Значение Пояснения
    StartPosition CenterScreen Открывать в центре экрана
    FormBorderStyle FixedDialog Запретить пользователю менять размер
    MaximizeBox false Отключить системную кнопку развертывания
    MinimizeBox falseStandardDialogs Отключить системную кнопку свертывания
    ShowInTaskbar false Запретить появление в панели задач
    AutoSize true Подстраиваться под содержимое
    AutoSizeMode GrowAndShrink Подстраиваться под содержимое (расширяться и сжиматься)
    Text Пусто Заголовок окна
  • Из свитка Containers панели инструментов Toolbox поместите на форму компоновочную панель FlowLayoutPanel и настройти ее в соответствии с таблицей
  • Таблица свойств компоновочной панели FlowLayoutPanel
    Свойство Значение Пояснения
    Name flow Имя компоновочной панели
    AutoSize true Подстраиваться под содержимое
    FlowDirection TopDown Размещать сверху вниз
    WrapContents false Не переносить дочерние элементы в следующий столбец
    Padding.All 8 Внутренний отступ дочерних элементов по периметру окна
    Dock Fill Распахнуть на всю клиентскую область родителя (формы)

    Эта панель будет автоматически следить за размещением своих дочерних элементов в соответствии с настройками.

  • Выделите на форме компоновочную панель flow, чтобы именно она принимала дочерние элементы, поместите в нее из свитка Common Controls текстовую метку Label и настройте ее свойства в соответствии с таблицей
  • Таблица свойств текстовой метки Label
    Свойство Значение Пояснения
    Name lblMessage Имя текстовой метки
    AutoSize true Подстраиваться под содержимое
    Anchor None Расположить посредине
    Margin.All 8 Отступ по наружному периметру текстовой метки
  • Аналогичным образом поместите в панель flow последовательно экземпляры компонентов TextBox и Button, которые настройте так
  • Таблица свойств поля ввода TextBox
    Свойство Значение Пояснения
    Name txtInput Имя текстовой метки
    Anchor None Расположить посредине
    Margin.All 8 Отступ по наружному периметру текстовой метки
    PasswordChar * Эхо ввода в текстовом поле

    Таблица свойств кнопки Button
    Свойство Значение Пояснения
    Name btnOk Имя кнопки
    AutoSize true Подстраиваться под содержимое
    Anchor None Расположить посредине
    Margin.All 8 Отступ по наружному периметру кнопки
    Text OK Надпись
    DialogResult OK Назначить статус "кнопки OK" в родительской форме

    Свойству дочерних кнопок формы DialogResult можно присвоить любое значение из перечисления System.Windows.Forms.DialogResult ( Abort, Cancel, Ignore, No, None, OK, Retry, 25_73 ). Оно и будет возвращено функцией ShowDialog() формы, если пользователь выберет именно эту кнопку. Если свойству DialogResult кнопки будет присвоен статус, отличный от None, то при щелчке пользователя на такой кнопке форма будет автоматически закрываться.

  • Подтяните низ формы до приемлемого размера, чтобы она стала выглядеть примерно так
  • Откройте файл InputPassword.cs в режиме View Designer, щелкните на заголовке формы и выполните команду Format/Lock Controls, чтобы защитить интерфейс формы от случайных изменений. Это групповая команда, которая устанавливает свойство Locked всех дочерних визуальных элементов и самой формы в значение True. То же самое можно сделать индивидуально для каждого элемента через меню Properties
  • Мы создали сам пользовательский интерфейс класса InputPassword диалогового окна. Теперь нужно настроить класс InputPassword, добавив туда метод создания диалогового окна и вызова его на экран.

  • Модифицируйте класс InputPassword следующим образом
  • using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Drawing;
    using System.Windows.Forms;
        
    namespace WinFormsApp
    {
        public partial class InputPassword : Form
        {
            public InputPassword()
            {
                InitializeComponent();
            }
        
            public InputPassword(string windowTitle, string message)
            {
                InitializeComponent();
        
                this.Text = windowTitle;
                lblMessage.Text = message;
            }
        
            public static string Show(string windowTitle, string message)
            {
                using(InputPassword inputDlg = 
                    new InputPassword(windowTitle, message))
                {
                    inputDlg.ShowDialog();
                    return inputDlg.txtInput.Text;
                }
            }
        }
    }

    Мы создали параметризованный конструктор для ввода заголовков диалогового окна в момент его создания. Мы добавили статический метод создания диалогового окна, который возвращает значение текстового поля после щелчка пользователем на кнопке, и такой метод нужно вызывать по имени класса. Упаковка создания экземпляра формы в блок using позволяет вызвать сборщик мусора сразу после выхода из этого блока.

    Теперь нужно поместить вызов окна запроса пароля в обработчик события Load запуска формы.

  • Откройте файл Start.cs в режиме View Designer, выделите форму через ее заголовок, перейдите в панель Properties, установите ее в режим Events, найдите событие Load и создайте для него обработчик Start_Load(). Заполните обработчик события так
  • private void Start_Load(object sender, System.EventArgs e)
        {
                string password = InputPassword.Show(
                    "Окно аутентификации пользователя",
                    "Просим ввести Ваш пароль:");
                if (password != "root")// Плохой способ хранения пароля
          {
            MessageBox.Show(
              "Извините, но Вам не разрешено\n" // Сообщение
              + "пользоваться этой суперпрограммой!!!",
              "Неверный пароль", // Заголовок окна
              MessageBoxButtons.OK, // Кнопка OK
              MessageBoxIcon.Stop);// Критическая иконка
            this.Close();
          }
        }
  • Запустите приложение, диалоговое окно ввода пароля должно выглядеть так
  • При неправильном пароле появляется простое диалоговое окно сообщений

    и приложение завершит свою работу.

    Добавление списка для запуска упражнений

    На стартовой форме мы создадим список с наименованиями упражнений, который будем пополнять по мере их выполнения. В окончательном варианте работы щелчок по пункту списка должен запускать дочернюю форму, соответствующую выполненному упражнению. Это удобно при демонстрации выполненной лабораторной работы.

  • Перейдите в режим Design, откройте в панели Toolbox вкладку Common Controls и двойным щелчком на компоненте ListBox создайте на форме его экземпляр
  • Выделите объект listBox1 и в панели Properties установите для него следующие значения свойств
  • Свойства объекта ListBox формы Start
    Свойство Значение
    Name generalList
    Dock Fill
    Items 1) Простое диалоговое окно со смайликами
  • Щелкните на заголовке формы и увеличьте ее ширину за маркеры так, чтобы поместилось все предложение в списке ListBox.
  • Через раскрывающийся список вверху панели Properties выделите объект generalList и установите для нее режим Events
  • Найдите событие SelectedIndexChanged и двойным щелчком на его поле значений создайте обработчик generalList_SelectedIndexChanged()
  • Теперь мы будем добавлять к приложению новые формы для выполнения каждого нового упражнения, регистрировать их в списке и помещать вызовы упражнений в этот обработчик главной формы.

    Упражнение 1. Смайлики

  • Выполните команду Project/Add Windows Form, чтобы добавить к проекту новую форму
  • Задайте имя новой форме Smiles.cs (Улыбки)
  • Поместите на форму три компонента PictureBox из вкладки Common Controls панели Toolbox, текстовую метку Label и одну кнопку Button. Все расположите так, как показано на снимке экрана (установите свойство label1.AutoSize =false )
  • Для выравнивания компонентов пользуйтесь командами меню оболочки, входящими в категорию Format, или одноименными кнопками панели инструментов Layout

  • Выполните команду меню Format/Lock Controls, чтобы закрепить расположение интерфейсных элементов на форме и, тем самым, защитить их от случайного сдвига или изменения размеров. Обратите внимание, что теперь на выделенных элементах маркеры сменились гладкой рамкой с пиктограммой замка
  • Теперь давайте установим для помещенных на форму объектов нужные свойства через панель Properties. При этом важно понимать, что все визуальные манипуляции с формой и помещенными на нее компонентами, в том числе и установка свойств через панель Properties, - это ничто иное, как удобный и наглядный способ генерации кода с помощью графических средств оболочки. Наша работа в режиме дизайна сопровождается параллельной работой оболочки в режиме кода. И все, что можно сделать через графический режим, можно сделать и вручную через код. Более того, код, набранный нами вручную, будет менее избыточным, чем это сделает оболочка по нашим визуальным инструкциям. Но забудем про расточительство, главное - удобство, быстрота и комфорт.

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

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

  • Задайте свойства размещенных на форме объектов через панель Properties в порядке их следования слева-направо, сверху-вниз, как указано в таблице
  • Значения свойств дочерних объектов формы Smiles
    Класс Свойство Значение Пояснения
    Form Text Smiles - Упражнение №1 Заголовок окна
      FormBorderStyle FixedDialog Запретили изменение размера окна формы
      MaximizeBox False Отключили системную кнопку развертывания окна
      MinimizeBox False Запретили системную кнопку свертывания окна
    PictureBox Name picSmile Идентификатор объекта ( улыбка )
      Image FACE02.ICO (возьмите из данной работы в каталоге Source. Используйте кнопку Import для радиокнопки Local resource ) Файл рисунка
      SizeMode StretchImage Опция - растянуть рисунок по размерам объекта
    PictureBox Name picFrown Идентификатор объекта ( хмурый взгляд )
      Image FACE04.ICO (возьмите из данной работы в каталоге Source. Используйте кнопку Import для радиокнопки Local resource ) Файл рисунка
      SizeMode StretchImage Опция - растянуть рисунок по размерам объекта
    PictureBox Name picHappy Идентификатор объекта ( счастливый )
      Image FACE03.ICO (возьмите из данной работы в каталоге Source. Используйте кнопку Import для радиокнопки Local resource ) Файл рисунка
      SizeMode StretchImage Опция - растянуть рисунок по размерам объекта
    Label Name lblMessage Идентификатор объекта ( сообщение )
      Text Щелкайте на смайликах Начальное содержимое текстовой метки
      Font/Name Arial Наименование шрифта
      Font/Size 14 Размер шрифта
      Font/Bold True Полужирный
      ForeColor Red Цвет переднего плана (красный)
      TextAlign MiddleCenter Выравнивание текста - середина по вертикали, центр по горизонтали
      BorderStyle Fixed3D Объемный вид элемента
    Button Name btnExit Идентификатор объекта
      Text Выход

    Надпись на кнопке

      AutoSize true Подстраиваться под размер надписи

    После всех настроек внешний вид формы должен быть примерно таким

    Разработку интерфейса первой дочерней формы на этом можно считать завершенной. Теперь пришла пора обеспечить ее функциональность.

  • Выделите первый смайлик picSmile и через панель Properties (в режиме Events ) создайте обработчик события Click
  • Заполните обработчик следующим кодом
  • private void picSmile_Click(object sender, System.EventArgs e)
        {
          picSmile.BorderStyle = BorderStyle.FixedSingle; // Рамка
          picFrown.BorderStyle = BorderStyle.None; // Нет рамки
          picHappy.BorderStyle = BorderStyle.None; // Нет рамки
          lblMessage.Text = "Щелкнули на первом рисунке";
        }
  • Двойным щелчком на втором рисунке ( picFrown ) создайте для него обработчик, который заполните так
  • private void picFrown_Click(object sender, System.EventArgs e)
        {
          picSmile.BorderStyle = BorderStyle.None; // Нет рамки
          picFrown.BorderStyle = BorderStyle.FixedSingle; // Рамка
          picHappy.BorderStyle = BorderStyle.None; // Нет рамки
          lblMessage.Text = "Щелкнули на втором рисунке";
        }
  • Двойным щелчком на третьем рисунке ( picHappy ) создайте для него обработчик, который заполните так
  • private void picHappy_Click(object sender, System.EventArgs e)
        {
          picSmile.BorderStyle = BorderStyle.None; // Нет рамки
          picFrown.BorderStyle = BorderStyle.None; // Нет рамки
          picHappy.BorderStyle = BorderStyle.FixedSingle; // Рамка
          lblMessage.Text = "Щелкнули на третьем рисунке";
        }
  • Двойным щелчком на кнопке btnExit создайте для нее обработчик, который заполните так
  • private void btnExit_Click(object sender, System.EventArgs e)
        {
          this.Close(); // Закрыть форму
        }

    Теперь подключим вызов этой дочерней формы к движку приложения, обеспечив возможность ее вызова по щелчку на соответствующей строке списка с упражнениями.

  • Сохраните проект командой меню File/Save All и закройте все окна редактирования командой Window/Close All Documents.
  • В панели Solution Explorer щелкните правой кнопкой мыши на файле Start.cs и выполните команду контекстного меню View Designer (или откройте файл в режиме дизайна двойным щелчком левой кнопки мыши).
  • Выделите элемент списка generalList и через панель Properties щелкните два раза на имени уже созданного обработчика в поле события SelectedIndexChanged, чтобы быстро позиционироваться к заголовку кода обработчика. Заполните обработчик следующим кодом
  • private void generalList_SelectedIndexChanged(object sender, System.EventArgs e)
        {
          switch(generalList.SelectedIndex + 1)
          {
            case 1:
              Smiles  frm1 = new Smiles();
              frm1.ShowDialog();
              break;    
          }
        }

    Здесь мы применили метод ShowDialog() класса Form (вместо метода Show() ). Это позволит нам открывать дочерние формы в модальном режиме (пока не закроется очередная форма, другие окна приложения не получат фокус ввода).

  • Выделите в режиме дизайна форму Start (щелкните на заголовке окна формы) и установите через панель Properties ee свойство StartPosition в значение CenterScreen, чтобы при первом запуске она появлялась в центре экрана
  • Откройте в режиме дизайна (в панели Solution Explorer ) форму Smiles, выделите ее через заголовок окна формы и установите свойство StartPosition в значение Manual. Проследите, чтобы свойство Location (размещение) имело значение ( 0, 0 ). Тем самым мы задали позицию появления дочерней формы в верхнем левом углу экрана.
  • Два последних действия позволят нам держать форму движка в центре экрана, а дочерние формы задвинуть в начало экрана (удобно для демонстрации упражнений, полезно для тренировки).

  • Запустите приложение и проверьте его работоспособность
  • На этапе построения формы бывает полезным сразу запускать ее для проверки. В нашем случае форма Smiles может быть вызвана только из главной формы. Исправим это.

  • Добавьте в конец класса Smiles следующую функцию-член Main(), которая позволит отображать форму первой при запуске приложения
  • public class Smiles : System.Windows.Forms.Form
      {
        ..............................................................
          
        private void btnExit_Click(object sender, System.EventArgs e)
        {
          this.Close(); // Закрыть форму
        }
      
        static void Main()
        {
          Application.Run(new Smiles());
        }
      }
  • Установите в качестве стартовой форму Smiles. Для этого выполните команду меню оболочки Project/WinFormsApp Properties и в появившемся диалоговом окне установите свойство Startup Object в значение WinFormsApp.Smiles
  • Запустите приложение и убедитесь, что теперь дочерняя форма Smiles стартует первой и единственной.
  • Краткое описание части компонентов панели Toolbox

    Вкладка All Windows Forms панели Toolbox содержит все компоненты, которые необходимы для быстрой разработки интерфейса пользователя. Она становится доступной, когда форма открыта в режиме Design и текущее приложение не запущено. Режим Design и компоненты панели Toolbox - это лишь инструменты для частичной автоматизации труда программиста. С их помощью быстро и синтаксически правильно оболочка генерирует код C# приложения в файле *.cs. Все компоненты поддерживаются соответствующими классами и доступны для управления ими программным путем.

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

    Некоторые компоненты панели Toolbox
    Компонент Назначение
    Pointer Установка курсора в режим выделения объектов.
    Button Инструмент для генерирования события щелчка, по которому вызывается функция - обработчик. В эту функцию можно разместить любой код, который требуется выполнить при щелчке на этом инструменте.
    CheckBox Дает возможность пользователю установить нужный режим из двух возможных. При обединении этих элементов в тематическую группу пользователь может производить множественные настройки нашего приложения.
    CheckedListBox Множество элементов CheckBox, объединенных в скролирующую группу.
    ColorDialog Стандартное диалоговое окно для предоставления пользователю возможности выбирать цвета
    ComboBox Раскрывающийся список. Состоит из верхней части с редактируемым текстовым полем, и нижней части со списком для выбора готовых элементов.
    ContextMenuStrip Контекстные меню обычно вызываются щелчком правой кнопкой мыши на нужном элементе управления формы. Туда обычно включают часто используемые команды из основного меню приложения. Это обеспечивает быстрый доступ пользователя к таким командам.
    DataGridView Этот элемент отображает данные в виде таблицы, состоящей из строк и столбцов. В простейшем случае этот элемент просто отображает все данные связанной с ним одной таблицы базы данных без всяких условий и позволяет оперировать с ними как в обычной электронной таблице. В более сложном случае элемент отображает выборку данных из нескольких связанных таблиц по некоторым условиям.
    DateTimePicker Этот элемент дает возможность пользователю быстро выбирать нужные дату из предоставляемого удобного интерфейса в виде календаря.
    DomainUpDown Представляет собой текстовое поле со стрелками для изменения значений списка вверх или вниз.
    ErrorProvider Этот элемент управления (невизуальный компонент) применяется для проверки правильности пользовательского ввода в допустимых пределах данных. Он предоставляет разработчику удобный интерфейс для оповещения пользователя о допущенных нарушениях и является лучшей заменой простому окну сообщений.
    FolderBrowserDialog Представляет собой диалоговое окно для навигации по папкам файловой системы компьютера.
    FontDialog Является стандартным диалоговоым окном, с помощью которого можно выбирать шрифты, установленные в настоящее время на текущем компьютере.
    GroupBox Применяется для связывания элементов управления в единую группу как дочерних. Используется для наглядности компактного размещения логически связанных элементов и обеспечения их согласованной работы. Перемещение элемента GroupBox в режиме дизайна в пределах формы приводит к одновременному перемещению всех включенных в группу элементов.
    HelpProvider Используется для связывания файлов справки (*.chm, *.htm) с приложением.
    HScrollBar Самостоятельный элемент управления, который присоединяется к другим элементам интерфейса для продвижения по большим массивам информации в горизонтальном направлении.
    ImageList Используется для хранения последовательности рисунков, подлежащих отображению приложением. Рисунки можно выбирать с помощью индексов списка и отображать на экране другими элементами управления.
    Label Простая текстовая метка для отображения нередактируемого текста на экране компьютера.
    LinkLabel Позволяет использовать текстовую метку в стиле гиперссылки. С помощью этого элемента часть текста можно связать с файлом, каталогом или Web-страницей.
    ListBox Отображает список элементов, из которых пользователь может выбрать один или несколько элементов. Если количество элементов в вписке превышает то, что может быть отображено, то автоматически добавляется вертикальная полоса прокрутки. При установке свойства MultiColumn в значение true добавляется горизонтальная полоса прокрутки. Если установлено в true свойство ScrollAlwaysVisible, то полоса прокрутки появляется всегда, независимо от количества элементов. Свойство SelectionMode устанавливает, сколько элементов списка может быть выделено одновременно. Свойство SelectedIndex возвращает индекс первого выделенного элемента в списке, начиная с нуля. Если нет выделенных элементов, свойство возвращает значение -1.
    ListView Отображает список элементов с иконками, наподобие правой области Windows Explorer. Элемент имеет четыре режима отображения: LargeIcon, SmallIcon, List, и Details.
    MenuStrip Создает главное меню формы, за пунктами которого можно закреплять различные команды управления приложением.
    MonthCalendar Обеспечивает привычный интерфейс работы с датой в виде календаря.
    NotifyIcon Используется для отображения в виде значков процессов, которые выполняются в фоновом режиме и долгое время не видны пользователю. Примером может служить программа антивирусной защиты, которую при необходимости пользователь может вызвать щелчком на уведомляющем значке в панели задач.
    NumericUpDown Представляет собой комбинацию текстового поля и пары стрелок, которые пользователь может применять для наглядного управления целым числовым значением.
    OpenFileDialog Представляет стандартное диалоговое окно открытия файла.
    PageSetupDialog Предоставляет стандартное диалоговое окно настройки страницы документа при печати.
    Panel Элемент Panel подобен элементу GroupBox. Применяется для связывания элементов управления в единую группу как дочерних. Используется для наглядности компактного размещения логически связанных элементов и обеспечения их согласованной работы. Имеет собственные полосы прокрутки, но не отображает заголовок.
    PictureBox Элемент служит для отображения рисунков в формате bitmap, GIF, JPEG, metafile, или icon. Отображаемый рисунок определяется свойством Image. Свойство SizeMode устанавливает режим согласования размеров элемента и рисунка. Рисунок отображается как в режиме разработки, так и во время выполнения приложения.
    PrintDialog Это стандартное диалоговое окно используется для настроек принтера перед печатью.
    PrintDocument Устанавливает, что печатать и как печатать. Может использоваться совместно с элементом PrintDialog для полного описания всех аспектов печати.
    PrintPreviewControl Позволяет предварительно просмотреть документ перед печатью, как он будет выглядеть после печати.
    PrintPreviewDialog Позволяет предварительно просмотреть документ перед печатью, как он будет выглядеть после печати. Отображает стандартное диалоговое окно с необходимыми элементами управления.
    ProgressBar Индикаторная линейка - отображает продвижение процесса в горизонтальном направлении.
    RadioButton Радиокнопка (переключатель)
    RichTextBox Представляет собой полноценный текстовый редактор.
    SaveFileDialog Обеспечивает стандартный настраиваемый диалог сохранения файлов.
    Splitter Используется для изменения относительных размеров склеенных элементов управления во время выполнения приложения.
    StatusBar Элемент создает строку состояния.
    TabControl Элемент для создания вкладок. Создает одну или несколько вкладок, на каждой из которых могут быть размещены другие объекты.
    TextBox Редактируемое текстовое поле.
    Timer Таймер
    ToolStrip Панель инструментов - контейнер для кнопок быстрого доступа.
    ToolTip Для создания всплывающих коротких подсказок, которые появляются при наведении курсора на элемент управления.
    TrackBar Регулятор для визуального изменения числовой информации (иногда называют Slider - бегунок).
    TreeView Отображает информацию в древовидном формате.
    VScrollBar Самостоятельный элемент управления, который присоединяется к другим элементам интерфейса для продвижения по большим массивам информации в вертикальном направлении.
    В панели Toolbox имеется возможность добавлять свои вкладки и копировать в них нужный набор инструментов из других вкладок. Добавить вкладку можно, щелкнув правой кнопкой мыши в любом месте панели Toolbox и выполнив команду контекстного меню Add Tab. Удалить вкладку можно, щелкнув правой кнопкой мыши на заголовке соответствующей вкладки и выполнив команду Delete Tab. Копировать нужные компоненты из одной вкладки в другую можно выполнением команд контекстного меню Copy и Paste.

    Упражнение 2. Простой калькулятор

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

  • Добавьте к проекту новую форму командой Project/Add Windows Form и задайте ей имя Calculate
  • Поместите на форму элементы из вкладки Common Controls панели Toolbox в соответствии с таблицей, чтобы пользовательский интерфейс формы был таким
  • Таблица свойств формы Calculate
    Элемент Свойство Значение
    Form Name Calculate
      StartPosition Manual
      Location 0; 0
      Text Простой калькулятор
      Icon Выбрать по усмотрению...(можно из Source)
      FormBorderStyle FixedDialog
    Label Name lblFirst
      Text Первое число:
      TextAlign MiddleRight
    Label Name lblSecond
      Text Второе число:
      TextAlign MiddleRight
    Label Name lblResult
      Text Результат:
      TextAlign MiddleRight
    TextBox Name txtFirst
      Text пусто
    TextBox Name txtSecond
      Text пусто
    TextBox Name txtResult
      Text пусто
      ReadOnly True
      TabStop False
    Button Name btnIncrement
      Text +
      Font/Bold True
      Font/Size 20
      Size 40; 40
    Button Name btnDecrement
      Text -
      Font/Name Courier New
      Font/Bold True
      Font/Size 20
      Size 40; 40
    Button Name btnIncrease
      Text *
      Font/Name Courier New
      Font/Bold True
      Font/Size 20
      Size 40; 40
    Button Name btnDivide
      Text :
      Font/Name Courier New
      Font/Bold True
      Font/Size 20
      Size 40; 40
    Button Name btnExit
      Text Выход

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

    Рекомендуемые префиксы для некоторых элементов управления
    Объект Префикс
    Button btn
    CheckBox chk
    ComboBox cmb
    DataGrid dat
    Form frm
    Label lbl
    ListBox lst
    MenuStrip mnu
    PictureBox pic
    RadioButton rad
    TextBox txt
  • Добавьте к классу Calculate функцию Main() для автономной отладки формы
  • static void Main()
        {
          Application.Run(new Calculate());
        }
  • Выполните команду меню WinFormsApp Properties и для вкладки Application установите в свойстве Startup Object форму Calculate стартовой
  • Защитите интерфейс формы Calculate от случайных изменений, выполнив команду Format/Lock Controls меню оболочки
  • Теперь нужно реализовать функциональность интерфейса. Прежде всего нужно защитить поля ввода от всех символов, кроме цифр, одного знака минус и одной точки. Стрелки и клавиша Del в текстовых полях функционируют, но работу клавиши Backspace нужно учесть явно.

  • Объявите в конце класса Calculate логическое поле isNumeric для отфильтровывания нецифровых символов, которые пользователь может попытаться ввести в текстовые поля
  • private bool isNumber = false;
  • Выделите текстовое поле txtFirst и через панель Properties в режиме Events создайте обработчик для события KeyDown. Заполните обработчик так
  • private bool isNumber = false;
      
        private void txtFirst_KeyDown(object sender, System.Windows.Forms.KeyEventArgs e)
        {
          isNumber = 
            e.KeyCode >= Keys.D0  e.KeyCode <= Keys.D9 // keyboard - основная клавиатура
            || e.KeyCode >= Keys.NumPad0  e.KeyCode <= Keys.NumPad9 // keypad - дополнительная клавиатура
            || e.KeyCode == Keys.Back;
        }
  • Выделите текстовое поле txtFirst и через панель Properties в режиме Events создайте обработчик для события KeyPress. Заполните обработчик так
  • private void txtFirst_KeyPress(object sender, System.Windows.Forms.KeyPressEventArgs e)
        {
          TextBox box = (TextBox) sender;// Явное преобразование типов
      
          switch(e.KeyChar) // Переключатель
          {
            case '-': // Разрешаем минус, если он первый
              if(box.Text.Length == 0)
                isNumber = true;
              break;
            case '.':  
              // Точка не должна быть первой
              if(box.Text.Length == 0)
                break;
              // Точка не должна следовать сразу за минусом
              if(box.Text[0] == '-'  box.Text.Length == 1)
                break;
              // Точка должна быть одна
              if(box.Text.IndexOf('.') == -1)
                isNumber = true; // Еще не было точек
              break;
          }
      
          // Запрещаем в текстовом поле лишние символы
          if(!isNumber)
            e.Handled = true;
        }
  • Выделите текстовое поле txtSecond и через панель Properties в режиме Events подключите к событиям KeyDown и KeyPress соответствующие обработчики, только что созданные для поля txtFirst. Обработчики подключите через раскрывающиеся списки полей значений
  • Здесь мы одни и те же обработчики используем для разных полей, поскольку необходимо выполнять одинаковые действия. Задача одна - не допускать для ввода в поля никакие другие символы, кроме цифр, одного минуса и одной точки. Возможность ввода цифр реализована для основной ( keyboard ) и дополнительной ( keypad ) частей клавиатуры. Параметр sender передает в обработчик ссылку на активное текстовое поле, вызвавшее событие редактирования.

    Конечно, программа будет более понятна, если для каждого элемента создавать свой обработчик. Но очень часто, как в нашем случае, преобладающая часть кода может быть совершенно одинакова в каждом обработчике. Тогда имеет смысл объединять несколько индивидуальных обработчиков в один. Какой подход выбрать - зависит от конкретной задачи и предпочтений программиста.

  • Добавьте в конец класса Calculate объявления числовых переменных, с которыми мы будем производить простые арифметические операции
  • // Объявляем числовые переменные как поля-члены класса
        // Их можно объявить как локальные и внутри обработчика btn_Click()
        // Но оставляем область видимости класс, вдруг где-нибудь еще пригодятся!
        private double numFirst, numSecond, numResult;
  • Перейдите в режим Design формы Calculate и выделите все четыре кнопки с операциями
  • Установите в панели Properties режим Events, найдите событие Click и введите вручную в поле значений этого события имя обработчика btn_Click
  • В созданный оболочкой общий обработчик для всех выделенных кнопок введите следующий код
  • // Один обработчик для всех кнопок-операций
        private void btn_Click(object sender, System.EventArgs e)
        {
          // Копируем текстовые поля в локальные переменные
          string strFirst = string.Copy(txtFirst.Text);
          string strSecond = string.Copy(txtSecond.Text);
      
          // Замена в строке точки символом запятой
          // для корректного преобразования в число
          int pos = strFirst.IndexOf('.');
          if(pos != -1)
          {
            strFirst = strFirst.Substring(0, pos)
              + ','
              + strFirst.Substring(pos + 1);
          }
          pos = strSecond.IndexOf('.');
          if(pos != -1)
          {
            strSecond = strSecond.Substring(0, pos)
              + ','
              + strSecond.Substring(pos + 1);
          }
      
          // Преобразуем текст в число для выполнения операций
          if(txtFirst.Text.Length > 0)
            numFirst = Convert.ToDouble(strFirst);
          else 
            numFirst = 0.0D;
          if(txtSecond.Text.Length > 0)
            numSecond = Convert.ToDouble(strSecond);
          else 
            numSecond = 0.0D;
      
          // Выполняем нужную операцию
          string btnText = "";// Создали строковую переменную
          bool divideFlag = false;// Флаг деления на ноль
          Button btn = (Button) sender;// Явное приведение типов для распознавания кнопок
          switch(btn.Name)// Переключатель
          {
            case "btnIncrement":// Операция сложения
              btnText = "\"+\"";// Экраны кавычек
              numResult = numFirst + numSecond;
              break;
            case "btnDecrement":// Операция вычитания
              btnText = "\"-\"";// Экраны кавычек
              numResult = numFirst - numSecond;
              break;
            case "btnIncrease":// Операция умножения
              btnText = "\"*\"";// Экраны кавычек
              numResult = numFirst * numSecond;
              break;
            case "btnDivide":// Операция деления
              btnText = "\":\"";// Экраны кавычек
              // Проверяем корректность деления
              if (Math.Abs(numSecond) < 1.0E-30)
              {
                MessageBox.Show(
                  "Делить на ноль нельзя!", // Сообщение
                  "Ошибка", // Заголовок окна
                  MessageBoxButtons.OK, // Кнопка OK
                  MessageBoxIcon.Stop);// Критическая иконка
                divideFlag = true;
              }
              else
                numResult = numFirst / numSecond;
              break;
          }
      
          // Для отображения в панели Output режима Debug
          System.Diagnostics.Debug.WriteLine("Нажата кнопка " + btnText);// Конкатенация
      
          // Отображение результата
          if(!divideFlag)
          {
            txtResult.Text = Convert.ToString(numResult);
            this.Validate(); // Обновить экран (можно убрать-излишне)
          }
        }

    Здесь мы прежде всего скопировали значения полей ввода в промежуточные текстовые переменные, используя статический метод System.String. Copy() класса String (псевдоним string ). Затем мы проверяем наличие символа "точки" в этих переменных и при обнаружении производим замену на символ "запятая" с полным формированием новой строки. Мы не можем заменить символ "на месте" в существующей строке, обратившись к нему как элементу массива, поскольку индексная форма адресации в строках существует только для чтения.

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

    Далее мы явно приводим переданную в обработчик ссылку типа object на нажатую кнопку к типу Button. В заголовке переключателя выделяем имя нажатой кнопки и выполняем соответствующую арифметическую операцию. Перед выполнением последней операции мы проверяем возможность возникновения случая " деления на ноль " и при его обнаружении предупреждаем пользователя выводом простого диалогового окна сообщений, отменяя саму операцию деления.

    После переключателя мы располагаем оператор вывода строки System.Diagnostics.Debug.WriteLine() с выполненной операцией в панель оболочки Output. Этот класс предназначен для работы с программой в отладочном режиме Debug и автоматически изымается из кода при компиляции окончательного варианта приложения в режиме Release.

    На последнем этапе, в коде обработчика, мы выводим результат в соответствующее текстовое поле с предварительным преобразованием типов. Затем мы даем команду системе обновить окно приложения, хотя в данном случае эта мера является излишней - система и так обновляет результат в текстовом поле.

    Теперь создадим обработчик нажатия на кнопку закрытия формы.

  • В режиме Design двойным щелчком на кнопке btnExit создайте обработчик, который заполните так
  • private void btnExit_Click(object sender, System.EventArgs e)
        {
          this.Close();
        }
  • Запустите проект и проверьте функциональность простого калькулятора
  • Теперь мы должны подключить разработанную форму калькулятора к основному окну приложения.

  • Установите в качестве стартовой форму Start. Для этого выполните команду меню оболочки Project/WinFormsApp Properties и в появившемся диалоговом окне установите для вкладки Application свойство Startup Object в значение WinFormsApp.Program
  • Откройте файл Start.cs в режиме View Code. Через раскрывающийся список Members в верхней части окна редактора кода найдите обработчик события generalList_SelectedIndexChanged(), который мы создали ранее, и дополните его вызовом окна калькулятора
  • private void generalList_SelectedIndexChanged(object sender, System.EventArgs e)
        {
          switch(generalList.SelectedIndex + 1)
          {
            case 1:
              Smiles  frm1 = new Smiles();
              frm1.ShowDialog();
              break;  
            case 2:
              Calculate frm2 = new Calculate();
              frm2.ShowDialog();
              break;
          }
        }
  • В панели Solution Explorer оболочки щелкните дважды на пиктограмме файла Start.cs, чтобы открыть его в режиме View Designer, выделите элемент списка в клиентской области формы и через панель Properties добавьте в свойство Items строку " 2) Простой калькулятор "
  • Запустите приложение и проверьте его работоспособность
  • Применение коллекций для предотвращения повторных запусков формы

    В C# под коллекцией понимается группа объектов, возможно, не одинаковых типов. Самым простым примером коллекции является обычный массив. Но в отличие от массива коллекции способны хранить объекты разных типов. Коллекции реализованы в виде классов, сгруппированных в пространстве имен System.Collections библиотеки mscorlib.dll

    C# - классы коллекций по сути аналогичны классам стандартной библиотеки шаблонов ( STL - Standard Template Library), определенной в C++. То, что в C++ называется контейнером, в C# именуется коллекцией. Коллекции упрощают программирование, предлагая уже готовые решения для построения структур данных, разработка которых "с нуля" потребовала бы больших затрат.

    Основное достоинство коллекций состоит в том, что они упрощают работу с группами объектов в прикладных программах. Все коллекции разработаны на основе набора четко определенных интерфейсов ( ICollection, IComparer, IDictionary и т.д.).

    Для контроля за запуском форм упражнений и предотвращения их повторного запуска можно использовать обычный массив, куда при каждом запуске очередной формы сохранять метку на форму и при повторной попытке проверять существование этой метки. Но недостатком использования массива является его фиксированный размер, определяемый однажды при создании массива. Коллекцию использовать удобнее, поскольку механизм автоматического изменения размера в нее уже встроен, и предусмотрен ряд полезных методов для управления коллекцией. Все коллекции предполагают использование цикла foreach (в каждом) для последовательного перебора всех элементов, входящих в коллекцию.

    Мы будем использовать класс ArrayList, представляющий собой массив переменной длины ( динамический массив ), элементами которого являются объектные ссылки. Только, для удобства и тренировки мы упакуем этот класс в свой класс, в котором предусмотрим необходимые нам методы и свойства. При этом мы не будем создавать для нового класса отдельный файл, а добавим его в файл Start.cs. Все методы класса и ссылку на коллекцию сделаем статическими, чтобы не создавать экземпляр класса в основном коде программы.

  • Добавьте в конец файла Start.cs после класса Start следующий код
  • // Класс для предотвращения повторных запусков форм
      public class Restart
      {
        // Создали коллекцию
        private static System.Collections.ArrayList frmList = 
          new System.Collections.ArrayList();
      
        // Метод для добавления метки в коллекцию
        public static void Add(Object frm)
        {
          frmList.Add(frm);
        }
      
        // Метод для удаления метки из коллекции
        public static void Remove(String str)
        {
          frmList.Remove(str);
        }
      
        // Метод, который отвечает на вопрос - запущена ли форма
        public static bool IsPresent(Object frm)
        {
          bool flag = false;
          foreach(Object x in frmList)
          {
            if(Object.Equals(x.ToString(), frm.ToString())) 
              flag = true;
          }
          return flag;
        }
      }
  • Найдите в файле Start.cs обработчик generalList_SelectedIndexChanged() и замените его тело на следующий код
  • private void generalList_SelectedIndexChanged(object sender, System.EventArgs e)
        {
          switch(generalList.SelectedIndex + 1)
          {
            case 1:
              Smiles frm1 = new Smiles();
              if(!Restart.IsPresent(frm1))
              {
                Restart.Add(frm1);
                frm1.Show();
              }
              break;  
            case 2:
              Calculate frm2 = new Calculate();
              if(!Restart.IsPresent(frm2))
              {
                Restart.Add(frm2);
                frm2.Show();
              }
              break;
          }
        }
  • В режиме дизайна форм Smiles и Calculate создайте обработчики для события FormClosed, которые заполните кодом удаления метки из коллекции при закрытии формы
  • private void Smiles_FormClosed(object sender, FormClosedEventArgs e)
            {
                Restart.Remove(this.ToString());
            }
    private void Calculate_FormClosed(object sender, FormClosedEventArgs e)
            {
                Restart.Remove(this.ToString());
            }
  • Запустите приложение и проверьте, что повторный запуск уже запущенной дочерней формы блокируется
  • В реализациях следующих упражнений этой лабораторной работы нам необходимо соблюдать введенную нами технологию предотвращения повторных запусков дочерних форм. Для этого в переключателе switch обработчика generalList_SelectedIndexChanged() нужно добавлять метку запущенной формы в коллекцию нашего класса Restart, а при закрытии дочерней формы необходимо удалять эту метку из коллекции в обработчике события FormClosed.

    Упражнение 3. Встраивание COM-объекта "Windows Media Player" в свое приложение

    В этом упражнении мы встроим мультимедиа - проигрыватель в наше приложение и создадим пользовательские элементы для управления им. Прежде всего нужно добавить этот COM -объект ( COM - Component Object Model - объектная модель компонентов) к панели инструментов Toolbox оболочки.

    Добавление своей вкладки в панель Toolbox оболочки

    Чтобы не смешивать набор элементов стандартных вкладок панели Toolbox, поместим этот элемент в отдельную вкладку.

    В панели Toolbox имеется возможность добавлять свои вкладки и копировать в них нужный набор инструментов из других вкладок. Добавить вкладку можно, щелкнув правой кнопкой мыши в любом месте панели Toolbox и выполнив команду контекстного меню Add Tab. Удалить вкладку можно, щелкнув правой кнопкой мыши на заголовке соответствующей вкладки и выполнив команду Delete Tab. Копировать нужные компоненты из одной вкладки в другую можно выполнением команд контекстного меню Copy и Paste.
  • Через панель Solution Explorer откройте любой файл проекта в режиме дизайна, чтобы стала доступна панель инструментов Toolbox. Щелкните правой кнопкой мыши на любом месте панели Toolbox и через контекстное меню выполните команду Add Tab
  • Присвойте добавленной вкладке имя " Моя вкладка " и раскройте ее
  • Присоединение COM-объекта к проекту

    Прежде всего нужно проследить за тем, чтобы перед функцией Main() в файле Start.cs стоял атрибут [STAThread], который сообщает среде исполнения, что основной программный поток приложения должен использовать однопоточную модель. Это необходимо для правильного взаимодействия с подсистемой COM.
  • Щелкните на новой вкладке правой кнопкой мыши и выполните команду контекстного меню Choose Items
  • В появившемся окне выберите вкладку COM Components, найдите в списке Windows Media Player, отметьте его и щелкните на кнопке OK
  • После этого в новой вкладке панели Toolbox появится пиктограмма выбранного компонента

    и его можно размещать на форме обычным образом.

    Замечание. Возможно, что оболочка на Вашем компьютере по умолчанию настроена на другой тип COM -компонента, который будет иметь другие свойства и события, чем используемый в этой работе. В этом случае щелкните на кнопке Browse вкладки COM Components окна выбора элементов Choose Toolboxs Items и в системном каталоге Windows/System32 выберите компонент msdxm.ocx. Это и будет интересующий нас компонент мультимедиа - проигрывателя.

    Добавление к приложению новой формы и ее разработка

  • Через меню оболочки выполните команду Project/Add Windows Form , чтобы добавить к проекту новую форму, и в появившемся диалоговом окне задайте имя файла формы MediaPlayer.cs
  • Визуальное создание и настройка COM-объекта

  • Поместите на форму с вкладки " Моя вкладка " компонент плеера. Форма после этого будет иметь такой вид
  • Выделите компонент видеоплейера на форме и через панель Properties задайте ему следующие свойства
  • Установка свойств компонента Windows Media Player
    Свойство Значение Пояснения
    Name Player Имя компонента
    AutoRewind True Автоперемотка, чтобы после просмотра видеоплеер устанавливался в начало
    AutoStart False Чтобы плеер не начинал проигрывать файл сразу после его открытия, а ждал отдельной команды на проигрывание
    ClickToPlay False Отключили возможность проигрывания/остановки по щелчку на самом плеере
    Size/Width 286 Можно настроить в визуальном режиме
    Size/Height 280 Можно настроить в визуальном режиме
  • Перейдите в режим редактирования кода файла MediaPlayer.cs и добавьте в конец класса MediaPlayer точку входа для автономного запуска вместе с атрибутом однопоточности [STAThread]
  • // Точка входа
        [STAThread]    
        static void Main()
        {
          Application.Run(new MediaPlayer());
        }
  • Выполните команду меню Project/WinFormsApp Properties и установите в свойстве Startup Object значение WinFormsApp.MediaPlayer, чтобы сделать форму плеера стартовой на период отладки
  • Если выделить компонент плеера и посмотреть его свойства в панели Properties, то можно увидеть много возможностей для его начальной настройки в режиме дизайна. Вот некоторые из свойств

    Некоторые свойства компонента плеера
    Свойство Пояснение
    Rate Темп воспроизведения. Если установить его значение, например, равным 2, то файл будет проигрываться в удвоенном темпе
    PlayCount Сколько раз повторять проигрывание файла. При значении 0 воспроизведение файла будет повторяться бесконечно
    FileName Файл для проигрывания
    Mute (немой) Начальное состояние кнопки включения звука
    ShowControls Показывать или нет встроенную панель управления плеером
    ShowTracker (буксир) Показывать или нет ползунок поиска проигрывателя
    ShowAudioControls Показывать или нет элементы управления динамиком
    ShowDisplay Показывать или нет информационную панель со сведениями о проигрываемом файле
    ShowPosicionControls Отключает панель управления позицией головки проигрывателя
    CurrentPosition Содержит значение, на какой секунде находится в данный момент воспроизведение файла
    Volume Громкость звука. Число 0 - самый громкий звук. Отрицательное число -10000 означает полную тишину
    Duration Свойство только для чтения, доступно программно. Содержит общую продолжительность проигрываемого файла в секундах

    Часть из этих свойств можно настроить через окно свойств самого компонента, если щелкнуть на нем правой кнопкой мыши. Это окно устанавливает те же самые свойства через более понятный интерфейс

    Добавление собственных элементов управления плеером

    Продублируем встроенные элементы управления плеером своими. Эти действия будем выполнять последовательно шаг за шагом, сразу программируя и проверяя их работу.

  • Увеличьте вниз размер формы так, чтобы освободить место для элементов управления. Разместите на форме из вкладки Containers панели Toolbox элемент управления GroupBox, который будет служить контейнером для наших элементов. Задайте ему свойства: Name = groupBox, Dock =Bottom, Text =" Мои элементы управления "
  • Поместите в верхней части контейнера groupBox четыре кнопки Button. Кнопки помещайте так: щелкайте на компоненте Button вкладки Common Controls панели Toolbox один раз, затем щелкайте внутри контейнера groupBox. Контейнер для кнопок будет родителем и может передавать им значения своих свойств, например, местоположение, цвет
  • Выровняйте кнопки, используя панель инструментов Layout оболочки
  • Замкните элементы управления групповой командой Format/Lock Controls, чтобы случайно не нарушить дизайн
  • Задайте кнопкам следующие свойства
  • Свойства кнопок нашей панели управления
    Элемент Свойство Значение Пояснения
    Button Name btnOpen Кнопка для открытия диалога выбора проигрываемого файла
    Text Open  
    Button Name btnPlay Кнопка для начала воспроизведения
    Text Play  
    Button Name btnStop Кнопка для остановки воспроизведения
    Text Stop  
    Button Name btnRewind Кнопка установки в начало воспроизведения
    Text Rewind  

    Теперь нужно запрограммировать наши кнопки в соответствии с решаемой задачей.

    Программирование кнопок

    Кнопка btnOpen должна загружать файл, предназначенный для проигрывания. Воспользуемся стандартным диалогом открытия файла, предусмотренным в библиотеке FCL.

  • Поместите из вкладки Dialogs панели Toolbox компонент OpenFileDialog. Это невизуальный компонент (неотображаемый на форме на этапе проектирования, а размещаемый в подвале окна редактирования оболочки), поэтому его экземпляр можно создать двойным щелчком на пиктограмме компонента
  • Настройте объект диалога открытия файла в соответствии с таблицей через панель Properties, предварительно выделив его в подвале графического редактора
  • Свойства экземпляра класса OpenFileDialog организации стандартного диалога
    Элемент Свойство   Значение
    OpenFileDialog Name   openFilePlayer
    Filter
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    Wave (Microsoft) (*.wav) |*.wav| 
    Dialogic VOX ADPCM (*.vox) |*.vox| 
    InterVoice (*.ivc) |*.ivc| 
    Macintosh AIFF (*.aif,*.aiff,*.snd) |*.aif,*.aiff,*.snd| 
    MP3 Audio (*.mp3) |*.mp3| 
    NeXT/Sun (Java) File (*.ai,*.snd) |*.ai,*.snd| 
    OggVorbis (*.ogg) |*.ogg|
    Perfect Clarity Audio (*.pca) |*.pca|
    QuickTime (*.mov) |*.mov|
    Raw File (*.raw) |*.raw|
    RealMedia (*.rm) |*.rm|
    Sound Designer 1 (*.dig,*.sd) |*.dig,*.sd|
    Video for Windows (*.avi) |*.avi|
    Windows Media (*asf) |*asf|
    Windows Media Audio (*.wma) |*.wma|
    Windows Media Video (*.wmv) |*.wmv|
    All Files (*.*) |*.*
    FilterIndex   13

    Свойство Filter предназначено для управления пользователем типом отображаемых файлов, а свойство FilterIndex устанавливает, какой фильтр появится первым при запуске окна. Фильтры в свойстве Filter следуют парами друг за другом " Название фильтра|шаблон_фильтра " и разделяются символом "Вертикальная черта".

    Внимание!!! Если вы будете копировать значение свойства Filter прямо из этой таблицы, то предварительно нужно убрать все невидимые символы перевода на новую строку (например, в блокноте), которые здесь введены в целях форматирования. Строка фильтра должна быть непрерывной. В шаблонах_фильтране должно быть пробелов ни внутри, ни в окружении, иначе фильтр не сработает.

    Создадим, как и в случае с калькулятором, один обработчик для всех размещенных ранее кнопок. Для этого выполните следующее...

  • Перейдите в режим дизайна для файла MediaPlayer.cs, выделите первую кнопку btnOpen и через панель Properties для события Click в поле его значений установите вручную имя обработчика btnClick
  • Разместите в созданном оболочкой обработчике следующий код
  • private void btnClick(object sender, System.EventArgs e)
        {
          Button btn = (Button) sender;// Явное приведение типов
          switch(btn.Name)
          {
            case "btnOpen":
              openFilePlayer.InitialDirectory = // Начальный каталог для фильтра
                System.IO.Directory.GetCurrentDirectory();// Каталог исполнимого файла
              openFilePlayer.ShowDialog();// Открываем диалог
              Player.FileName = openFilePlayer.FileName;// Передаем имя файла в плеер
              break;
          }
        }
  • Подсоедините обработчик btnClick к остальным кнопкам. Для этого откройте панель Properties в режиме Events, выделите оставшиеся три кнопки вместе и через раскрывающийся список в поле значения свойства Click выберите обработчик btnClick
  • Дополните код обработчика btnClick так
  • private void btnClick(object sender, System.EventArgs e)
        {
          Button btn = (Button) sender;// Явное приведение типов
          switch(btn.Name)
          {
            case "btnOpen":
              openFilePlayer.InitialDirectory = // Начальный каталог для фильтра
                System.IO.Directory.GetCurrentDirectory();// Каталог исполнимого файла
              openFilePlayer.ShowDialog();// Открываем диалог
              Player.FileName = openFilePlayer.FileName;// Передаем имя файла в плеер
              break;
            case "btnPlay":
              Player.Play();
              break;
            case "btnStop":
              Player.Stop();
              break;
            case "btnRewind":
              Player.CurrentPosition = 0;
              break;
          }
        }

    После завершения работы стандартного диалогового окна OpenFileDialog его свойство FileName либо содержит полное (вместе с путем) имя выбранного файла, либо пустую строку, если пользователь отказался от выбора.

    Теперь мы готовы к испытанию формы. Запустите приложение и загрузите какой-нибудь звуковой- или видео файл (например, прилагаемый к данной работе в каталоге Source файл " WellWait - 02.AVI "). Поэкспериментируйте с кнопками - они все работают.

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

  • Использовать операторы обработки исключений try...catch
  • Блокировать кнопку btnPlay до тех пор, пока не будет загружен файл для проигрывания
  • Мы воспользуемся вторым способом. Для начального блокирования кнопки есть три пути:

  • Установить свойство Enabled кнопки на этапе проектирования в состояние False
  • Программно установить свойство Enabled кнопки в состояние false в конструкторе класса MediaPlayer
  • Создать для формы обработчик события Load и разместить в нем код установки кнопки в недоступное состояние
  • Мы воспользуемся последним способом. При этом будем блокировать все кнопки, кроме btnOpen, чтобы лишний раз не вводить в заблуждение нашего дорогого пользователя.

  • Перейдите в режим View Designer формы, выделите форму щелчком на ее заголовке или через раскрывающийся список панели Properties, установите панель Properties в режим Events и создайте обработчик события Load формы двойным щелчком на поле значений этого события. Заполните обработчик следующим кодом
  • private void MediaPlayer_Load(object sender, System.EventArgs e)
        {
          btnPlay.Enabled = btnStop.Enabled = btnRewind.Enabled = false;
        }

    Здесь мы употребили сцепленную операцию присваивания.

    Теперь нужно разблокировать кнопки после того, как будет загружен файл в проигрыватель. Для этого

  • Дополните обработчик btnClick следующим кодом
  • private void btnClick(object sender, System.EventArgs e)
        {
          Button btn = (Button) sender;// Явное приведение типов
          switch(btn.Name)
          {
            case "btnOpen":
              openFilePlayer.InitialDirectory = // Начальный каталог для фильтра
                System.IO.Directory.GetCurrentDirectory();// Каталог исполнимого файла
              openFilePlayer.ShowDialog();// Открываем диалог
              Player.FileName = openFilePlayer.FileName;// Передаем имя файла в плеер
              if(Player.FileName.Length > 0)
              {
                // Перебираем все дочерние элементы контейнера GroupBox
                foreach(Control obj in groupBox.Controls)
                {
                  // Выделяем полное имя типа вместе с пространствами имен
                  String str = obj.GetType().ToString();
                  // Ищем позицию последней точки
                  int pos = str.LastIndexOf('.');
                  // Выделяем имя типа без пути
                  str = str.Substring(pos + 1);
                  if(str == "Button")
                    obj.Enabled = true;
                }
              }
              break;
            case "btnPlay":
              Player.Play();
              break;
            case "btnStop":
              Player.Stop();
              break;
            case "btnRewind":
              Player.CurrentPosition = 0;
              break;
          }
        }

    В добавленном коде мы проверяем, что выбранное пользователем имя файла непустое (надо было все-таки поставить обработчик исключения, поскольку пользователь может выбрать файл, не подлежащий проигрыванию. Но пока хватит и этого!).

    Родительские элементы, такие как Panel, GroupBox, TabControl, сама форма Form, имеют свойство Controls, которое является коллекцией и содержит ссылки на все помещенные на родительский элемент дочерние компоненты - наследники класса Control.

    Мы перебираем в цикле foreach ( -для каждого ) все элементы коллекции GroupBox, находим среди них кнопки и устанавливаем их доступными. Здесь мы наворотили лишние проверки на тот случай, если кроме кнопок в контейнере GroupBox окажутся и элементы других типов, хотя на данном этапе кроме кнопок мы туда ничего не помещали.

  • Запустите проект и убедитесь, что все добавленные нами возможности управления работают правильно.
  • Добавление к форме других элементов управления

    Усовершенствуем схему управления медиаплеером. Задействуем возможности управления звуком и контроля позиции проигрывающей головки. Для этого нам понадобятся такие элементы управления вкладки All Widows Forms, как TrackBar ( ползунок ), CheckBox ( флажок ), ProgressBar ( индикатор процесса, индикатор прогресса ), TextBox ( текстовое поле ).

  • Сместите кнопку btnRewind влево на один уровень с кнопкой btnOpen и поместите на освободившееся справа место элемент CheckBox (один щелчок на CheckBox, затем щелчок внутри контейнера groupBox ). Этот элемент даст возможность пользователю отключать или включать звук при воспроизведении файла
  • Правее элемента CheckBox разместите в контейнере groupBox текстовое поле TextBox, которое мы будем использовать для отображения численного значения величины звука
  • Ниже разместите в контейнере groupBox элемент TrackBar для плавного регулирования звука
  • Теперь нужно настроить эти элементы управления. Начнем с элемента CheckBox. Этот элемент мы будем использовать для отключения звука плеера. Настройте его свойства так

    Свойства элемента CheckBox для отключения звука
    Свойство Значение
    Name checkVolume
    CheckAlign MiddleLeft
    Image VOLUME01.ICO (возьмите из данной работы в каталоге Source. Используйте кнопку Import для радиокнопки Local resource )
    ImageAlign BottomRight
    Checked True
    Text ПУСТО

    Давайте сразу запрограммируем этот элемент. При каждом щелчке на элементе CheckBox изменяется его булево свойство CheckedCheckState ).

  • Создайте в панели Properties обработчик события CheckedChanged элемента checkVolume и добавьте в него следующий код
  • private void checkVolume_CheckedChanged(object sender, System.EventArgs e)
        {
          // Это наше извращение, можно сразу обращаться к checkVolume
          CheckBox check = (CheckBox) sender;
      
          // В каком состоянии оказался CheckBox
          if(check.CheckState == CheckState.Checked)
          {
            Player.Mute = false;
          }
          else
          {
            Player.Mute = true;
          }
        }

    Для плавного изменения звука мы воспользуемся элементом TrackBar. Свойства и методы элемента TrackBar аналогичны полосам прокрутки ScrollBar. Некоторые из них перечислены в таблице. Причем не все свойства элемента TrackBar доступны в режиме проектирования, зато все доступны в программном режиме на этапе выполнения.

    Некоторые свойства элемента TrackBar, доступные в режиме View Designer
    Свойство Пояснения
    Value Главная регулируемая величина, определяющая текущее состояние головки бегунка. По умолчанию начальное значение равно значению свойства Minimum
    SmallChange Минимальная дискретность изменения величины Value при управлении стрелками или перемещением головки бегунка с захватом мышью. По умолчанию установлено 1
    LargeChange Максимальная дискретность изменения величины Value при нажатии клавиш PageUp или PageDown, или щелчках мышью на шкале элемента. По умолчанию установлено 5
    Minimum Нижний предел значения Value. По умолчанию 0
    Maximum Верхний предел значения Value. По умолчанию 10
    TickFrequency Свойство целого типа, определяющее частоту делений на шкале ползунка. Расчитывается с использованием значений свойств Minimum и Maximum
    TickStyle Определяет форму ползунка при отображении пользователю
  • Настройте свойства элемента TrackBar так
  • Свойства элемента TrackBar для регулирования величины звука
    Свойство Значение
    Name trackVolume
    Location 8; 104
    Size 272; 53
    Minimum 0
    Maximum 50
    Orientation Horizontal
    LargeChange 5
    SmallChange 1
    TickFrequency 5
    TickStyle BottomRight
  • Присвойте элементу TextBox имя txtVolume
  • Элемент txtVolume будет только отображать числовое значение Volume плеера, поэтому запретим его редактирование пользователем.

  • Выделите элемент txtVolume и создайте через панель Properties для его события KeyPress обработчик, который заполните так
  • private void txtVolume_KeyPress(object sender, System.Windows.Forms.KeyPressEventArgs e)
        {
          // Запрещаем редактировать поле, кроме клавиши Del
          // и горизонтальных стрелок - они встроены в элемент
          e.Handled = true;
        }

    Свойство Handled сообщает элементу, что все уже обработано и нужно успокоиться и ничего не делать. Элемент TrackBar имеет событие Scroll, которое происходит каждый раз, когда изменяется положение головки бегунка. Воспользуемся этим, чтобы менять численное значение величины Volume плеера.

  • Создайте для события Scroll элемента TrackBar обработчик, который заполните так
  • private const int maxVolume = 0;
        private const int minVolume = -5000;
        private void trackVolume_Scroll(object sender, System.EventArgs e)
        {
          TrackBar track = (TrackBar) sender;
          float minValue = track.Minimum;
          float maxValue = track.Maximum;
          float value = track.Value;
          // Формула линейного изменения свойства  Player.Volume
          // (самая простая, хотя можно вставить и нелинейный закон)
          Player.Volume = minVolume - 
            (int) ( (value - minValue) /(maxValue - minValue) 
                    * minVolume );
          txtVolume.Text = Convert.ToString(Player.Volume);
        }

    Теперь нужно установить начальные значения текстового поля и положения бегунка при первой загрузке формы

  • Добавьте в обработчик события Load формы, который мы уже создали раньше, следующий код
  • private void MediaPlayer_Load(object sender, System.EventArgs e)
        {
          btnPlay.Enabled = btnStop.Enabled = btnRewind.Enabled = false;
          txtVolume.Text = Convert.ToString(Player.Volume);// Отображаем величину звука
          trackVolume.Value = // Устанавливаем бегунок
            // Поскольку работаем с целыми, которые округляются,
            // то вначале умножаем, потом делим
            trackVolume.Minimum + (minVolume - Player.Volume)
            * (trackVolume.Maximum - trackVolume.Minimum) 
            / minVolume;
        }

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

  • Добавьте в обработчик checkVolume_CheckedChanged() следующий код блокирования ползунка
  • private void checkVolume_CheckedChanged(object sender, System.EventArgs e)
        {
          // Это наше извращение, можно сразу обращаться к checkVolume
          CheckBox check = (CheckBox) sender;
      
          // В каком состоянии оказался CheckBox
          if(check.CheckState == CheckState.Checked)
          {
            Player.Mute = false;
            trackVolume.Enabled = true;
          }
          else
          {
            Player.Mute = true;
            trackVolume.Enabled = false;
          }
        }

    Теперь мы хотим сделать так, чтобы пользователь мог видеть по нашему интерфейсу, какая часть файла уже воспроизведена. Для этого используем индикатор прогресса (процесса) ProgressBar.

    Есть еще альтернативный вариант - COM-индикатор Microsoft ProgressBar Control 6.0 (SP4). Этот индикатор можно загрузить на панель Toolbox точно также, как мы это делали для плеера.

    Откройте вкладку панели Toolbox "Моя вкладка", которую мы создали ранее, щелкните на ней правой кнопкой мыши и выполните команду Coose Items. Установите в появившемся окне вкладку COM Components, найдите нужный элемент Microsoft ProgressBar Control 6.0 (SP4), отметьте его и нажмите кнопку OK. Теперь этот компонент можно помещать на форму обычным образом.

    Некоторые свойства:

  • Scrolling - гладкий или прерывистый вид полосы
  • Min, Max - пределы изменения полосы
  • Value - текущее значение
  • Orientation - горизонтальное или вертикальное расположение полосы
  • Appearance, BorderStyle - внешний вид полосы
  • Поместите компонент ProgressBar в контейнер groupBox (щелчком там и там) и настройте через панель Properties его свойства так
  • Свойства элемента ProgressBar
    Свойство Значение
    Name progressBar
    Location 16; 160
    Size 256; 8

    Здесь мы установили только интерфейсные свойства элемента, а существенные свойства по управлению элементом будем задавать программно.

  • Выровняйте интерфейсные элементы с применением панели инструментов Layout оболочки, чтобы панель имела на данном этапе примерно такой вид
  • Выделите элемент Player и на панели Properties в режиме Events найдите событие ReadyStateChange. Создайте двойным щелчком на поле значений этого события обработчик Player_ReadyStateChange(), который заполните так
  • private void Player_ReadyStateChange(object sender, AxMediaPlayer._MediaPlayerEvents_ReadyStateChangeEvent e)
        {
          progressBar.Minimum = 0;
          int maximum = progressBar.Maximum = (int)Player.Duration;
        }

    Этот обработчик будет срабатывать каждый раз при загрузке нового файла и устанавливать новые значения свойств диапазона индикатора прогресса в секундах.

  • Вновь выделите элемент Player и на панели Properties в режиме Events найдите событие PositionChange. Создайте двойным щелчком на поле значений этого события обработчик Player_PositionChange(), который заполните так
  • private void Player_PositionChange(object sender, AxMediaPlayer._MediaPlayerEvents_PositionChangeEvent e)
        {
          progressBar.Value = (int)Player.CurrentPosition;
        }

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

  • Добавьте двойным щелчком во вкладке All Windows Forms на компоненте Timer таймер к нашей форме и назначьте ему имя timer
  • Создайте для его единственного события Tick обработчик, в котором продублируйте код обработчика Player_PositionChange(), обновляющий позицию элемента progressBar
  • private void timer_Tick(object sender, System.EventArgs e)
        {
          progressBar.Value = (int)Player.CurrentPosition;
    //      progressBar.PerformStep();// Для альтернативного способа
        }
  • Дополните обработчик Player_ReadyStateChange() события загруки медиафайла кодом настройки и запуска таймера
  • private int  countSteps;
        private void Player_ReadyStateChange(object sender, AxMediaPlayer._MediaPlayerEvents_ReadyStateChangeEvent e)
        {
          countSteps = 50; // Количество шагов индикатора прогресса
          progressBar.Minimum = 0;
          progressBar.Maximum = (int)Player.Duration;
          timer.Interval = (progressBar.Maximum - progressBar.Minimum) 
            * 1000 // Переводим секунды в миллисекунды
            / countSteps; // Операция деления на последнем месте
          timer.Start();
          progressBar.Value = progressBar.Minimum;
    /*      // Для альтернативного способа
          progressBar.Step = (progressBar.Maximum - progressBar.Minimum) 
            / countSteps;
    */        
        }

    Красным цветом выделен альтернативный код управления интикатором. Но если вы его будете использовать, то нужно позаботиться об остановке таймера при каждой остановке проигрывания и о его запуске при продолжении проигравания. Если этого не сделать, то при остановке проигрывания индикатор будет продолжать показывать процесс, поскольку таймер не будет остановлен.

  • Выделите форму через ее заголовок и установите два свойства в следующие значения
  • FormBorderStyle=FixedSingle
  • MaximizeBox=False
  • Теперь осталось подключить эту форму к основному окну приложения и сделать необходимые настройки.

  • Создайте обработчик события FormClosed формы MediaPlayer, как мы это делали в предыдущих случаях данной работы для предотвращения повторного запуска, и заполните его так
  • private void MediaPlayer_FormClosed(object sender, System.EventArgs e)
        {
          Restart.Remove(this.ToString());
        }
  • Измените заголовок формы, задав ее свойству Text значение " Упражнение №3 - MediaPlayer "
  • Через панель Solution Explorer откройте файл Start.cs в режиме кода и добавьте к обработчику generalList_SelectedIndexChanged() следующий код
  • private void generalList_SelectedIndexChanged(object sender, System.EventArgs e)
        {
          switch(generalList.SelectedIndex + 1)
          {
          .................................................
            case 3:
              MediaPlayer frm3 = new MediaPlayer();
              if(!Restart.IsPresent(frm3))
              {
                Restart.Add(frm3);
                frm3.Show();
              }
              break;
          }
        }
  • Через панель Solution Explorer откройте файл Start.cs в режиме дизайна двойным щелчком на пиктограмме. Выделите через панель Properties список generalList и добавьте в его свойство Items следующую строку

    3) Собственный Windows Media Player

  • Командой меню оболочки Project/WinFormsApp Properties выберите вкладку Application и верните свойство Startup Object в значение WinFormsApp.Program
  • Запустите приложение, загрузите медиафайл, испытайте элементы управления и полюбуйтесь на свою работу. Просмотрите мультик, прилагаемый к работе
  • Вернуться к учебному плану