Шаблон формы для работы с классом
Можно предложить следующий образец формы, предназначенной для поддержки работы с объектами некоторого класса. Напомню, каждый класс представляет тип данных. Операции над типом данных можно разделить на три категории: конструкторы, команды и запросы. Конструкторы класса позволяют создать соответствующий объект; команды, реализуемые процедурами, изменяют состояние объекта; запросы, реализуемые функциями без побочных эффектов, возвращают информацию о состоянии объекта, не изменяя самого состояния. Исходя из этого, можно сконструировать интерфейс формы, выделив в нем три секции. В первой секции, разделенной на три раздела, будут представлены команды, запросы и конструкторы. Следующая секция выделяется для окон, в которые можно вводить аргументы исполняемых команд. Последняя секция предназначается для окон, в которых будут отображаться результаты запросов.
На рис. 24.3 показана форма для списка с курсором, построенная в соответствии с описанным шаблоном.
Рис. 24.3. Форма для списка с курсором, построенная по образцу
Список с курсором имеет группу команд, позволяющих перемещать курсор влево, вправо, к началу и концу списка, к элементу с заданным номером. Другая группа команд позволяет производить операции по вставке элементов слева или справа от курсора, удалять элемент, отмеченный курсором. Еще одна группа позволяет производить поиск элементов в списке. Запросы позволяют получить данные об активном элементе, отмеченном курсором, определить число элементов в списке и получить другую полезную информацию.
Работа со списками (еще один шаблон)
Для организации интерфейса разработано большое число элементов управления, часть из них показана на рис. 24.1. Все они обладают обширным набором свойств, методов и
событий, их описание может занять отдельную книгу. Такие элементы, как, например, ListView, TreeView, DataGrid, несомненно, заслуживают отдельного рассмотрения, но не здесь и не сейчас. Я ограничусь более подробным разбором лишь одного элемента управления - ListBox, - позволяющего отображать данные в виде некоторого списка.
Элемент управления класса ListBox
Во многих задачах пользователю предлагается некоторый список товаров, гостиниц, услуг и прочих прелестей, и он должен выбрать некоторое подмножество элементов из этого списка. Элемент управления ListBox позволяет собрать в виде списка некоторое множество объектов и отобразить для каждого объекта связанную с ним строку. Он дает возможность пользователю выбрать из списка один или несколько элементов.
В списке могут храниться строки, тогда объект совпадает с его отображением. Если же хранятся объекты, то в классе объекта следует переопределить метод ToString, возвращаемый результат которого и будет строкой, отображаемой в списке.
Давайте рассмотрим главный вопрос: как список заполняется элементами? Есть несколько разных способов. Новой и интересной технологией, применимой к самым разным элементам управления, является связывание элемента управления с данными, хранящимися в различных хранилищах, прежде всего, в базах данных. Для этого у списка есть ряд свойств - DataBinding и другие. Эта технология заслуживает отдельного рассмотрения, я о ней только упоминаю, но рассматривать ее не буду. Рассмотрим три других способа.
Заполнить список элементами можно еще на этапе проектирования. Для этого достаточно выбрать свойство Items: появится специальное окно для заполнения списка строками - элементами списка. Добавлять объекты других классов таким способом невозможно.
Но это можно делать при программной работе со свойством Items, возвращающим специальную коллекцию объектов, которая задана классом ObjectCollection. Эта коллекция представляет объекты, хранимые в списке, и является основой для работы со списком. Класс ObjectCollection предоставляет стандартный набор методов для работы с коллекцией - вставки, удаления и поиска элементов. Метод Add позволяет добавить новый объект в конец коллекции, метод Insert позволяет добавить элемент в заданную позицию, указанную индексом. Метод AddRange позволяет добавить сразу множество элементов, заданное обычным массивом, массивом класса ListArray или коллекцией, возвращаемой свойством Items другого списка. Для удаления элементов используются методы Remove, RemoveAt, Clear. Метод Contains позволяет определить, содержится ли заданный объект в коллекции, а метод IndexOf позволяет определить индекс такого элемента. Коллекция может автоматически сортироваться, для этого достаточно задать значение true свойства Sorted, которым обладает список ListBox.
Еще один способ задания элементов списка поддерживается свойством DataSource, значение которого позволяет указать источник данных, ассоциируемый со списком. Понятно, что этот способ является альтернативой коллекции, задаваемой свойством Items. Так что, если источник данных определен свойством DataSource, то нельзя использовать методы класса ObjectCollection - Add и другие для добавления или удаления элементов списка, - необходимо изменять сам источник данных.
Главное назначение элемента ListBox - предоставить пользователю возможность осуществлять выбор из отображаемых списком элементов. Свойство SelectionMode позволяет указать, сколько элементов разрешается выбирать пользователю - один или несколько. Для работы с отобранными элементами имеется ряд свойств. SelectedItem и SelectedIndex возвращают первый отобранный элемент и его индекс. Свойства SelectedItems и SelectedIndices возвращают коллекции, заданные классами
SelectedObjectCollection и SelectedIndexCollection, которые дают возможность анализировать все отобранные пользователем объекты. Методы Contains и IndexOf позволяют определить, выбрал ли пользователь некоторый элемент. Добавлять или удалять элементы из этих коллекций нельзя.
Среди других методов и свойств ListBox - упомяну свойство MultiColumn, с помощью которого можно организовать показ элементов списка в нескольких столбцах; свойство HorizonalScrollBar, задающее горизонтальный скроллинг; методы BeginUpdate и EndUpdate, позволяющие повысить эффективность работы со списком. Все методы по добавлению и удалению элементов, стоящие после BeginUpdate, не будут приводить к перерисовке списка, пока не встретится метод EndUpdate.
У элемента управления ListBox большое число событий, с некоторыми из которых мы встретимся при рассмотрении примеров. Перейдем теперь к рассмотрению примеров работы с этим элементом управления и, как обещано, построим некоторый шаблон, демонстрирующий работу с двумя списками, когда пользователь может переносить данные из одного списка в другой и обратно. На рис. 24.4 показано, как выглядит форма, реализующая данный шаблон.
Рис. 24.4. Шаблон формы для обмена данными двух списков
На форме показаны два списка - listBox1 и listBox2, между которыми расположены две командные кнопки. Обработчик события Click первой кнопки переносит выбранную группу элементов одного списка в конец другого списка, (если включено свойство Sorted, то автоматически поддерживается сортировка списка). Переносимые элементы удаляются из первого списка. Вторая кнопка реализует операцию переноса всех элементов списка. Направление переноса - из левого списка в правый и обратно - задается заголовками (">", ">>") или ("<", "<<"), изображенными на кнопках. Заголовки меняются автоматически в обработчиках события Enter, возникающих при входе в левый или правый списки - listBox1 или listBox2. Еще две командные кнопки, как следует из их заголовков, предназначены для закрытия формы с сохранением или без сохранения результатов работы пользователя. Таково общее описание шаблона. А теперь рассмотрим реализацию. Начнем с обработчиков события Enter наших списков:
private void listBox1_Enter(object sender, System.EventArgs e)
{
/*** Событие Enter у списка возникает при входе в список ***/
button1.Text = ">"; button2.Text = ">>";
}
private void listBox2_Enter(object sender,
System.EventArgs e)
{
/*** Событие Enter у списка возникает при входе в список ***/
button1.Text = "<"; button2.Text = "<<";
}
Посмотрим, как устроены обработчики события Click для командных кнопок, осуществляющих перенос данных между списками:
private void button1_Click(object sender, System.EventArgs e)
{
/* Обработчик события Click кнопки "> <"
* Выборочный обмен данными между списками
* ListBox1 <-> ListBox2******************/
if(button1.Text == ">")
MoveSelectedItems(listBox1, listBox2);
else
MoveSelectedItems(listBox2, listBox1);
}
private void button2_Click(object sender, System.EventArgs e)
{
/* Обработчик события Click кнопки ">> <<"
* Перенос всех данных одного списка в конец другого списка
* ListBox1 <-> ListBox2******************/
if(button2.Text == ">>")
MoveAllItems(listBox1, listBox2);
else
MoveAllItems(listBox2, listBox1);
}
Обработчики событий устроены достаточно просто - они вызывают соответствующий метод, передавая ему нужные аргументы в нужном порядке. Рассмотрим метод, переносящий множество отобранных пользователем элементов из одного списка в другой:
private void MoveSelectedItems(ListBox list1, ListBox list2)
{
/*** Выделенные элементы списка list1 ****
*** помещаются в конец списка List2 *****
*** и удаляются из списка list1 ********/
list2.BeginUpdate();
foreach (object item in list1.SelectedItems)
{
list2.Items.Add(item);
}
list2.EndUpdate();
ListBox.SelectedIndexCollection indeces = list1.SelectedIndices;
list1.BeginUpdate();
for (int i = indeces.Count -1; i>=0 ; i--)
{
list1.Items.RemoveAt(indeces[i]);
}
list1.EndUpdate();
}
Некоторые комментарии к этому тексту. Заметьте, для добавления выделенных пользователем элементов к другому списку используется коллекция SelectedItems и метод Add, поочередно добавляющий элементы коллекции. Метод AddRange для добавления всей коллекции здесь не проходит:
list2.Items.AddRange(list1.SelectedItems);
поскольку нет автоматического преобразования между коллекциями ObjectCollection и SelectedObjectCollection.
Для удаления выделенных элементов из списка list1 используется коллекция индексов. Обратите внимание, при удалении элемента с заданным индексом из любой коллекции индексы оставшихся элементов автоматически пересчитываются. Поэтому удаление элементов происходит в обратном порядке, начиная с последнего, что гарантирует корректность оставшихся индексов.
Намного проще устроен метод, переносящий все элементы списка:
private void MoveAllItems(ListBox list1, ListBox list2)
{
/*** Все элементы списка list1 ****
**** переносятся в конец списка list2 ****
**** список list1 очищается *************/
list2.Items.AddRange(list1.Items);
list1.Items.Clear();
}
Добавим еще одну функциональную возможность - разрешим переносить элементы из одного списка в другой двойным щелчком кнопки мыши. Для этого зададим обработчики события DoubleClick наших списков:
private void listBox1_DoubleClick(object sender,
System.EventArgs e)
{
/* Обработчик события DoubleClick левого списка
* Выбранный элемент переносится в правый список
* ListBox1 <-> ListBox2******************/
MoveSelectedItems(listBox1, listBox2);
}
private void listBox2_DoubleClick(object sender,
System.EventArgs e)
{
/* Обработчик события DoubleClick правого списка
* Выбранный элемент переносится в левый список
* ListBox1 <-> ListBox2******************/
MoveSelectedItems(listBox2, listBox1);
}
Обработчики вызывают уже рассмотренные нами методы.
На этом закончим рассмотрение функциональности проектируемого образца формы. Но, скажете вы, остался не заданным целый ряд вопросов: непонятно, как происходит заполнение списков, как сохраняются элементы после завершения переноса, обработчики события Click для двух оставшихся кнопок не определены. Ничего страшного. Сделаем нашу форму родительской, возложив решение оставшихся вопросов на потомков, пусть каждый из них решает эти вопросы по-своему.
Yandex.RTB R-A-252273-3- 1. Лекция: Visual Studio .Net, Framework .Net
- Открытость
- Модульность
- Виртуальная машина
- Дизассемблер и ассемблер
- Метаданные
- Сборщик мусора - Garbage Collector - и управление памятью
- Исключительные ситуации
- События
- Общие спецификации и совместимые модули
- 2. Лекция: Язык c# и первые проекты
- Создание c#
- Виды проектов
- Консольный проект
- Windows-проект
- Начало начал - точка "большого взрыва"
- Выполнение проекта по умолчанию после "большого взрыва"
- Проект WindowsHello
- Общий взгляд
- Система типов
- Типы или классы? и типы, и классы
- Семантика присваивания
- Преобразование к типу object
- Примеры преобразований
- Семантика присваивания. Преобразования между ссылочными и значимыми типами
- Операции "упаковать" и "распаковать" (boxing и unboxing).
- 4. Лекция: Преобразования типов
- Где, как и когда выполняются преобразования типов?
- Преобразования ссылочных типов
- Преобразования типов в выражениях
- Преобразования внутри арифметического типа
- Преобразования и класс Convert
- Проверяемые преобразования
- Исключения и охраняемые блоки. Первое знакомство
- Опасные вычисления в охраняемых проверяемых блоках
- Опасные вычисления в охраняемых непроверяемых блоках
- Опасные преобразования и методы класса Convert
- 5. Лекция: Переменные и выражения
- Объявление переменных
- Время жизни и область видимости переменных
- Глобальные переменные уровня модуля. Существуют ли они в c#?
- Int X,y; //координаты точки
- Локальные переменные
- Глобальные переменные уровня процедуры. Существуют ли?
- Константы
- Выражения
- Приоритет и порядок выполнения операций
- Перегрузка операций
- Операции sizeof и typeof
- Как получить подробную информацию о классе?
- Статические поля и методы арифметических классов
- Логические операции
- Условное выражение
- Операция приведения к типу
- Присваивание
- Специальные случаи присваивания
- Определенное присваивание
- Еще раз о семантике присваивания
- Рассмотрим объявления:
- Класс Math и его функции
- Класс Random и его функции
- Блок или составной оператор
- If(выражение_1) оператор_1
- If(выражение1) if(выражение2) if(выражение3) ...
- Оператор switch
- Операторы break и continue
- Циклы While
- Цикл foreach
- Процедуры и функции - функциональные модули
- Процедуры и функции - методы класса
- Процедуры и функции. Отличия
- Описание методов (процедур и функций). Синтаксис
- Список формальных аргументов
- Тело метода
- Вызов метода. Синтаксис
- О соответствии списков формальных и фактических аргументов
- Вызов метода. Семантика
- Поля класса или функции без аргументов?
- Пример: две версии класса Account
- Функции с побочным эффектом
- Методы. Перегрузка
- 10. Лекция: Корректность методов. Рекурсия
- Корректность методов
- Инварианты и варианты цикла
- Рекурсия
- Рекурсивное решение задачи "Ханойские башни"
- Быстрая сортировка Хоара
- 11. Лекция: Массивы языка c#
- Общий взгляд
- Динамические массивы
- Многомерные массивы
- Массивы массивов
- Процедуры и массивы
- Класс Array
- Массивы как коллекции
- Сортировка и поиск. Статические методы класса Array
- Сводка свойств и методов класса Array
- Класс Object и массивы
- Массивы объектов
- Массивы. Семантика присваивания
- Общий взгляд
- Класс char[] - массив символов
- Операции над строками
- Строковые константы
- Неизменяемый класс string
- Статические свойства и методы класса String
- Метод Format
- Методы Join и Split
- Динамические методы класса String
- Операции над строками
- Основные методы
- Емкость буфера
- Пространство имен RegularExpression и классы регулярных выражений
- Немного теории
- Синтаксис регулярных выражений
- Классы Match и MatchCollection
- Классы Group и GroupCollection
- Пример "чет и нечет"
- Пример "око и рококо"
- Пример "кок и кук"
- Пример "обратные ссылки"
- Пример "Дом Джека"
- Пример "Атрибуты"
- 16. Лекция: Классы
- Синтаксис класса
- Поля класса
- Доступ к полям
- Методы-свойства
- Индексаторы
- Константы
- Конструкторы класса
- Деструкторы класса
- Проектирование класса Rational
- Методы класса Rational
- Закрытый метод нод
- Операции над рациональными числами
- Константы класса Rational
- Развернутые и ссылочные типы
- Классы и структуры
- Класс Rational или структура Rational
- Встроенные структуры
- Еще раз о двух семантиках присваивания
- Перечисления
- Персоны и профессии
- 18. Лекция: Отношения между классами. Клиенты и наследники
- Отношения между классами
- Отношения "является" и "имеет"
- Отношение вложенности
- Расширение определения клиента класса
- Отношения между клиентами и поставщиками
- Сам себе клиент
- Наследование
- Добавление полей потомком
- Конструкторы родителей и потомков
- Добавление методов и изменение методов родителя
- Статический контроль типов и динамическое связывание
- Три механизма, обеспечивающие полиморфизм
- Пример работы с полиморфным семейством классов
- Абстрактные классы
- Классы без потомков
- Преобразование к классу интерфейса
- Наследование от общего предка
- Клонирование и интерфейс iCloneable
- Сериализация объектов
- Класс с атрибутом сериализации
- Интерфейс iSerializable
- 20. Лекция: Функциональный тип в c#. Делегаты
- Как определяется функциональный тип и как появляются его экземпляры
- Функции высших порядков
- Вычисление интеграла
- Построение программных систем методом "раскрутки". Функции обратного вызова
- Наследование и полиморфизм - альтернатива обратному вызову
- Делегаты как свойства
- Операции над делегатами. Класс Delegate
- Пример "Плохая служба"
- 21. Лекция: События
- Классы с событиями
- Класс sender. Как объявляются события?
- Делегаты и события
- Как зажигаются события
- Классы receiver. Как обрабатываются события
- Классы с событиями, допустимые в каркасе .Net Framework
- Пример "Списки с событиями"
- Класс sender
- Классы receiver
- Переопределение значений аргументов события
- Классы с большим числом событий
- Проект "Город и его службы"
- 22. Лекция: Универсальность. Классы с родовыми параметрами
- Наследование и универсальность
- Синтаксис универсального класса
- Класс с универсальными методами
- Два основных механизма объектной технологии
- Стек. От абстрактного, универсального класса к конкретным версиям
- Ограниченная универсальность
- Синтаксис ограничений
- Список с возможностью поиска элементов по ключу
- Как справиться с арифметикой
- Родовое порождение класса. Предложение using
- Универсальные делегаты
- Framework .Net и универсальность
- 23. Лекция: Отладка и обработка исключительных ситуаций
- Корректность и устойчивость программных систем
- Жизненный цикл программной системы
- Искусство отладки
- Отладочная печать и условная компиляция
- Классы Debug и Trace
- Метод Флойда и утверждения Assert
- Выбрасывание исключений. Создание объектов Exception
- If !MyMethod(){// обработка ошибки}
- Параллельная работа обработчиков исключений
- Блок finally
- Класс Exception
- Организация интерфейса
- Форма и элементы управления
- Взаимодействие форм
- Модальные и немодальные формы
- Передача информации между формами
- Шаблон формы для работы с классом
- Наследование форм
- Два наследника формы TwoLists
- Огранизация меню в формах
- Создание меню в режиме проектирования
- Классы меню
- Создание инструментальной панели с командными кнопками
- Методы класса Graphics
- Класс Pen
- Класс Brush
- Событие Paint
- Кисти и краски
- 25. Лекция: Финальный проект
- Абстрактный класс Figure
- Класс Circle
- Список с курсором. Динамические структуры данных
- Классы элементов списка
- Организация интерфейса