Задания для самостоятельного выполнения
Решение
Создайте новый проект PhoneBook в решении Lab13.
1-й этап.Создадим визуальный интерфейс приложения (рис. 13.1).
Поместите на форму семь компонентов Label, четыре компонента TextBox, два компонента NumericUpDown, один компонент MaskedTextBox и два компонента Button.
Измените значения свойства Text всех меток Label и формы Form1 в соответствии с рис. 13.1.
Свойства компонентов установите следующим образом:
Компонент | Свойство | Значение |
form1 | Name | MainForm |
FormBorderStyle | FixedSingle | |
StartPosition | CenterScreen | |
textBox1 | Name | LastNameTextBox |
textBox2 | Name | NameTextBox |
textBox3 | Name | PatronymicTextBox |
textBox4 | Name | StreetTextBox |
numericUpDown1 | Name | HouseNumericUpDown NumericUpDown NumericUpDown NumericUpDown |
Minimum | ||
Maximum | ||
numericUpDown2 | Name | FlatNumericUpDown |
Minimum | ||
Maximum | ||
maskedTextBox1 | Name | PhoneMaskedTextBox |
Свойство FormBorderStyle формы, установленное в FixedSingle указывает, что пользователь не сможет изменить размеры формы, а свойство StartPosition, равное CenterScreen, означает, что при запуске форма будет расположена в центре экрана.
Вы переименовали основную форму в MainForm. Переименуйте также и файл этой формы. Для этого в Solution Explorer выделите имя Form1.cs, щелкните правой кнопкой мыши, выберите команду Rename и дайте файлу имя MainForm.cs.
Выделите все четыре компонента TextBox, оба компонента NumericUpDown и компонент MaskedTextBox и установите для них значение свойства Enabled в False.
Измените свойства компонентов Button следующим образом:
Компонент | Свойство | Значение |
Button1 | Name | PreviousButton |
Text | < | |
Font.Size | ||
Font.Bold | True | |
TabIndex | ||
Button2 | Name | NextButton |
Text | > | |
Font.Size | ||
Font.Bold | True | |
TabIndex |
Свойство Mask компонента MaskedTextBox используют, чтобы обеспечить ввод данных в соответствии с заданной маской. Если пользователь вводит не совместимые с маской символы, MaskedTextBox игнорирует их.
Для ввода маски выделите компонент PhoneMaskedTextBox, в окне свойств Properties найдите свойство Mask и щелкните по кнопке в правом столбце. В открывшемся диалоговом окне Input Mask задайте маску “(999) 000-000” или выберите стандартную маску Phone Number из списка.
С помощью мыши выделите все компоненты на форме (кроме кнопок) и измените значение свойства Font.Size на 12. Расположите все компоненты на форме ровно.
Положите на форму компонент StatusStrip (строка состояния). Заметьте, что значок с именем этого компонента отображается на вкладке MainForm.cs[Design] ниже формы “Телефонный справочник”. Напомним, что это происходит для некоторых компонентов, которые не имеют графического отображения на форме или обладают сложной составной структурой. Добавьте на строку состояния четыре элемента StatusLabel (рис. 13.2). Для удобства можно временно увеличить ширину формы.
Измените свойства следующим образом.
Компонент | Свойство | Значение |
toolStripStatusLabel1 | Name | Quantity_ToolStripStatusLabel |
Text | Количество записей | |
BorderSides | All | |
BorderStyle | SunkenOuter | |
toolStripStatusLabel2 | Name | QuantityToolStripStatusLabel |
AutoSize | False | |
Size.Width | ||
Text | ||
BorderSides | All | |
BorderStyle | SunkenOuter | |
toolStripStatusLabel3 | Name | Number_ToolStripStatusLabel |
Text | Номер записи | |
BorderSides | All | |
BorderStyle | SunkenOuter | |
toolStripStatusLabel4 | Name | NumberToolStripStatusLabel |
AutoSize | False | |
Size.Width | ||
Text | ||
BorderSides | All | |
BorderStyle | SunkenOuter |
Поместите на форму компонент MenuStrip (меню). Переименуйте его в MainMenuStrip.
Добавьте пункт меню “Абонент”, и подпункт меню “Добавить” (рис. 13.3).
Форма MainForm – это основная форма проекта, на которой можно будет просматривать абонентов справочника, а также вызывать основные методы его обработки. В частности, при выборе команды “Добавить” должна открываться другая форма, на которой будут вводиться данные про нового абонента, а при закрытии второй формы данные с нее будут передаваться в основную форму и добавляться к списку.
Итак, добавим в проект еще одну форму. Напомним, что для этого необходимо выполнить команду Project – Add Windows Form. Введите имя новой формы AddForm.cs (рис. 13.4).
Большинство компонентов формы AddForm совпадает с частью компонентов формы MainForm. Чтобы не повторять одни и те же действия дважды, скопируем эти компоненты. Для этого выделите семь компонентов Label, четыре компонента TextBox, два компонента NumericUpDown, один компонент MaskedTextBox с формы MainForm и нажмите<Ctrl+Insert>. Затем перейдите на форму AddForm и нажмите <Shift+Insert>.
Свойство Text формы установите равным “Добавление абонента”. Для всех компонентов, в которых будут вводиться данные, установите значение свойства TabIndex от 0 до 6 последовательно.
Добавьте на форму AddForm одну кнопку. Задайте ее свойства в соответствии со следующей таблицей:
Компонент | Свойство | Значение |
Button1 | Name | AddButton |
Text | Добавить | |
Font.Size | ||
Font.Bold | True | |
TabIndex |
2-й этап.Создание программного кода.
Предположим, что длина полей LastName (фамилия), Name (имя), Patronymic (отчество) не превосходит 25 символов, а Street (улица) – 40 символов. Измените свойства MaxLength компонентов TextBox в соответствии с введенными ограничениями.
Добавим к проекту класс Note для хранения полей абонента телефонного справочника. Для этого в окне Solution Explorer выделим имя проекта PhoneBook и, щелкнув правой кнопкой мыши, выберем команду Add – Class. В появившемся окне введем имя Note.cs и нажмем Ok.
Класс Note опишем следующим образом (не забудьте указать модификатор доступа public):
public class Note
{
public string LastName;
public string Name;
public string Patronymic;
public string Street;
public ushort House;
public ushort Flat;
public string Phone;
}
Далее в классе формы MainForm опишем поле PhoneNote для хранения списка абонентов телефонного узла и целочисленную переменную current, которая будет отвечать за номер выводимой в текущий момент записи:
public partial class MainForm : Form
{
private List<Note> PhoneNote;
private int current;
…
В конструкторе класса MainForm создадим объект PhoneNote и инициализируем переменную current следующим образом:
public MainForm()
{
InitializeComponent();
PhoneNote = new List<Note>();
current = -1;
}
Отметим, что нумерация элементов в списке происходит с нуля. Значение переменной current, равное –1, означает, что список пуст и в текущий момент никакая запись не выводится.
Напишем метод PrintElement(), который выводит текущую запись (с номером current) на форму MainForm (скопируйте этот метод в класс формы сразу после конструктора). Метод PrintElement()будет вызываться из разных обработчиков программы многократно.
private void PrintElement()
{
if ((current >= 0) && (current < PhoneNote.Count))
{ // если есть что выводить
// MyRecord - запись списка PhoneNote номер current
Note MyRecord = PhoneNote[current];
// записываем в соответствующие элементы на форме
// поля из записи MyRecord
LastNameTextBox.Text = MyRecord.LastName;
NameTextBox.Text = MyRecord.Name;
PatronymicTextBox.Text = MyRecord.Patronymic;
PhoneMaskedTextBox.Text = MyRecord.Phone;
StreetTextBox.Text = MyRecord.Street;
HouseNumericUpDown.Value = MyRecord.House;
FlatNumericUpDown.Value = MyRecord.Flat;
}
else // если current равно -1, т. е. список пуст
{ // очистить поля формы
LastNameTextBox.Text = "";
NameTextBox.Text = "";
PatronymicTextBox.Text = "";
PhoneMaskedTextBox.Text = "";
StreetTextBox.Text = "";
HouseNumericUpDown.Value = 1;
FlatNumericUpDown.Value = 1;
}
// обновление строки состояния
NumberToolStripStatusLabel.Text = (current + 1).ToString();
QuantityToolStripStatusLabel.Text = PhoneNote.Count.ToString();
}
Отметим, что обратиться к любому элементу можно с помощью метода ElementAt(), а также просто указывая номер элемента в квадратных скобках после имени списка (как при обращении к элементу массива), т. е. следующие два оператора равнозначны.
Note MyRecord = PhoneNote[number];
Note MyRecord = PhoneNote.ElementAt(number);
Напишем обработчик выбора подпункта меню “Добавить”. Для создания обработчика можно стандартным образом найти в окне Properties на вкладке Events событие Click, а можно просто дважды щелкнуть по самому подпункту.
private void добавитьToolStripMenuItem_Click(object sender, EventArgs e)
{
// создаем запись - экземпляр класса Note
Note MyRecord = new Note();
// создаем экземпляр формы AddForm
AddForm _AddForm = new AddForm(MyRecord);
// открываем форму для добавления записи
_AddForm.ShowDialog();
// текущей записью становится последняя
current = PhoneNote.Count;
// добавляем к списку PhoneNote новый элемент - запись MyRecord,
// взятую из формы AddForm
PhoneNote.Add(_AddForm.MyRecord);
// выводим текущий элемент
PrintElement();
}
Поясним код. В первой строке определяем и создаем локальную переменную MyRecord. Далее создаем экземпляр класса формы AddForm (назовем его _AddForm) с параметром MyRecord и открываем форму. После закрытия формы будет выполнено следующее: переменная current становится равной количеству записей в списке (заметьте, что это выполняется до добавления элемента, т. е. в итоге эта переменная будет на единицу меньше количества элементов списка, а учитывая, что нумерация элементов происходит с нуля, это как раз и будет номер последнего элемента списка), запись MyRecord из формы _AddForm добавляется в список абонентов телефонного справочника PhoneNote, вызывается метод PrintElement(), который выведет запись с номером current, т. е. последнюю.
Далее откроем форму AddForm. Во-первых, в классе формы опишем переменную для хранения записи. Для нее укажем директиву public, чтобы это поле было доступно из класса формы MainForm.
public partial class AddForm : Form
{
public Note MyRecord;
…
Далее изменим конструктор формы – добавим к нему параметр _MyRecord, имеющий тип Note. В теле конструктора значение параметра переписывается в поле MyRecord.
public AddForm(Note _MyRecord)
{
InitializeComponent();
MyRecord = _MyRecord;
}
Напишем обработчик нажатия на кнопку AddButton.
private void AddButton_Click(object sender, EventArgs e)
{
// определяем поля записи -
// берем значения из соответствующих компонентов на форме
MyRecord.LastName = LastNameTextBox.Text;
MyRecord.Name = NameTextBox.Text;
MyRecord.Patronymic = PatronymicTextBox.Text;
MyRecord.Phone = PhoneMaskedTextBox.Text;
MyRecord.Street = StreetTextBox.Text;
MyRecord.House = (ushort)HouseNumericUpDown.Value;
MyRecord.Flat = (ushort)FlatNumericUpDown.Value;
Close(); // закрываем форму
}
Сохраните проект. Запустите его и попробуйте добавить в телефонную книгу информацию о себе и своем друге. Убедитесь, что в строке состояния отображается, что количество записей равно двум, номер записи равен двум.
Дополним приложение PhoneBook возможностью перемещаться по записям телефонного справочника. Для перехода к предыдущей записи опишем обработчик события Click кнопки PreviousButton:
private void PreviousButton_Click(object sender, EventArgs e)
{
current--; // уменьшаем номер текущей записи на 1
PrintElement(); // выводим элемент с номером current
}
Код прост: номер текущего элемента уменьшается на единицу, после чего выводится текущая запись с номером current.
Сохраните проект. Запустите и протестируйте приложение; определите, какая ошибка возникает и почему.
Задания для самостоятельного выполнения
3.1.Добавьте в обработчик события Click кнопки PreviousButton условный оператор, обрабатывающий ошибку, возникающую при переходе на предыдущую запись, если текущей записью является первая (в этом случае выдавайте сообщение “Предыдущей записи не существует!”).
3.2.Напишите обработчик события нажатия на кнопку NextButton . Не забудьте проверить случай перехода на следующую запись, если текущей записью является последняя, номер которой равен PhoneNote.Count – 1 (в этом случае выдавайте сообщение “Следующей записи не существует!”).
Упражнение 13.2. Дополним приложение “Телефонный справочник” следующими возможностями:
– считывание информации об абонентах из текстового файла,
– сохранение информации об абонентах в текстовый файл.
Решение
Напомним, что при файловом вводе и выводе в .NET Framework наиболее часто используются следующие классы:
– File – содержит методы для работы с файлами (создание, копирование, удаление);
– Directory – содержит методы для работы с директориями;
– StreamWriter – позволяет осуществлять запись в файл;
– StreamReader – позволяет осуществлять чтение из файла.
1-й этап.Доработаем визуальный интерфейс приложения.
Добавьте в меню MainMenu пункт “Файл”, и подпункты меню “Открыть” и “Сохранить”.
Поместите на форму компоненты SaveFileDialog (диалог сохранения файла) и OpenFileDialog (диалог открытия файла).
2-й этап.Создание программного кода.
В разделе подключения пространств имен (первые строчки файла MainForm.cs) добавьте строку:
using System.IO;
Пространство имен System.IO содержит классы для работы с файлами и каталогами: File, Directory, StreamReader, StreamWriter и др.
Создайте обработчик события выбора подпункта меню “Сохранить” (дважды щелкнув по этому подпункту) и поместите туда следующий код:
if (saveFileDialog1.ShowDialog() == DialogResult.OK)
// Если в диалоговом окне нажали ОК
{
try // обработчик исключительных ситуаций
{
// используя sw (экземпляр класса StreamWriter),
// создаем файл с заданным в диалоговом окне именем
using (StreamWriter sw =
new StreamWriter(saveFileDialog1.FileName))
{
// проходим по всем элементам списка
foreach (Note MyRecord in PhoneNote)
{
// записываем каждое поле в отдельной строке
sw.WriteLine(MyRecord.LastName);
sw.WriteLine(MyRecord.Name);
sw.WriteLine(MyRecord.Patronymic);
sw.WriteLine(MyRecord.Street);
sw.WriteLine(MyRecord.House);
sw.WriteLine(MyRecord.Flat);
sw.WriteLine(MyRecord.Phone);
}
}
}
catch (Exception ex) // перехватываем ошибку
{
// выводим информацию об ошибке
MessageBox.Show("Не удалось сохранить данные! Ошибка: " +
ex.Message);
}
}
Поясним код. Метод ShowDialog() компонента SaveFileDialog отображает диалоговое окно сохранения файла. Если пользователь нажал кнопку “OK”, будем выполнять сохранение. Используя sw – экземпляр класса StreamWriter, – создаем файл с заданным в диалоговом окне именем, в цикле foreach просматриваем все записи списка PhoneNote и заносим их в файл.
Оператор try позволяет перехватить ошибки (исключительные ситуации), которые могут возникнуть в процессе сохранения данных в файл, и в этом случае пользователю выводится сообщение с информацией о произошедшей ошибке.
Создайте обработчик события выбора пункта меню “Открыть”.
Note MyRecord;
if (openFileDialog1.ShowDialog() == DialogResult.OK)
// если в диалоговом окне нажали ОК
{
try // обработчик исключительных ситуаций
{
// считываем из указанного в диалоговом окне файла
using (StreamReader sr =
new StreamReader(openFileDialog1.FileName))
{
// пока не дошли до конца файла
while (!sr.EndOfStream)
{
//выделяем место под запись
MyRecord = new Note();
// считываем значения полей записи из файла
MyRecord.LastName = sr.ReadLine();
MyRecord.Name = sr.ReadLine();
MyRecord.Patronymic = sr.ReadLine();
MyRecord.Street = sr.ReadLine();
MyRecord.House = ushort.Parse(sr.ReadLine());
MyRecord.Flat = ushort.Parse(sr.ReadLine());
MyRecord.Phone = sr.ReadLine();
//добавляем запись в список
PhoneNote.Add(MyRecord);
}
}
// если список пуст, то current устанавливаем в -1,
// иначе текущей является первая с начала запись (номер 0)
if (PhoneNote.Count == 0) current = -1;
else current = 0;
// выводим текущий элемент
PrintElement();
}
catch (Exception ex) // если произошла ошибка
{
// выводим сообщение об ошибке
MessageBox.Show("При открытии файла произошла ошибка: "+
ex.Message);
}
}
Поясним код обработчика. Метод ShowDialog() компонента OpenFileDialog отображает диалоговое окно открытия файла. Если пользователь нажал кнопку “OK”, будем выполнять считывание из файла. Используя экземпляр класса StreamReader, открываем файл с заданным в диалоговом окне именем, в цикле while считываем строки данных из файла, пока не дойдем до конца файла. При считывании формируем новые элементы типа Note и добавляем их к списку PhoneNote. Далее переопределяем значение переменной current – либо на первую запись (номер 0), либо в –1, если записей в списке нет. Последним действием отображаем на форме текущий элемент списка (с номером current); напомним, что в методе PrintElement() есть проверка списка на пустоту, и если элементов в списке нет, то ничего выводиться не будет, поля на форме будут очищены.
Добавим, что если справочник уже содержал записи, то при открытии новые элементы добавляются в конец списка.