При нажатии на Сумма в примере ArbitraryMethod из Лекция 7, VS 2013 выдается ошибка: Необработанное исключение типа "System.InvalidOperationException" в System.Windows.Forms.dll Дополнительные сведения: Недопустимая операция в нескольких потоках: попытка доступа к элементу управления "lblResult" не из того потока, в котором он был создан. Затем: Необработанное исключение типа "System.InvalidOperationException" в mscorlib.dll Дополнительные сведения: Для каждой асинхронной операции метод EndInvoke может вызываться только один раз. |
Работа с элементами управления (продолжение)
Сохранение настроек приложения. XML-сериализация
При работе с приложением часто возникает необходимость сохранения пользовательских настроек. Одним из способов решения этой задачи является преобразование свойств и полей объекта в специальное представление — формат XML. При этом данные преобразуются в последовательную серию байтов. Этот процесс называется XML-сериализацией. Обратный процесс — восстановление записанной информации — называется десериализацией.
Создайте новое Windows-приложение и назовите его XML-serialization. В качестве свойств для сохранения будем использовать ширину и высоту самой формы.
Подключаем пространство имен для работы с потоками и XML-сериализацией:
using System.IO; using System.Xml.Serialization;
Создаем новый класс FormSize, в котором объявляем переменные для хранения размеров формы:
public class FormSize { public int height; public int width; }
Размеры формы должны записываться при закрытии формы. В режиме дизайна выделяем форму и в окне Properties переключаемся на события формы (нажимаем на кнопку Events). Создаем обработчик для события Closing формы:
private void Form1_Closing (object sender, System.ComponentModel.CancelEventArgs e) { //Создаем экземпляр frmSize класса FormSize: FormSize frmSize = new FormSize(); // Присваиваем текущие значения высоты и ширины формы //переменным height и width frmSize.height = this.Height; frmSize.width = this.Width; //Cоздаем экземпляр xmlser класса XmlSerializer XmlSerializer xmlser = new XmlSerializer(typeof(FormSize)); //Создаем переменную filename, которой присваиваем //название файла applicationSettings.xml в текущей директории string filename = System.Environment.CurrentDirectory + "\\applicationSettings.xml"; //Создаем поток filestream для создания XML-файла FileStream filestream = new FileStream(filename, FileMode.Create); //Создаем сериализацию для экземпляра frmSize xmlser.Serialize(filestream, frmSize); //Закрываем поток filestream.Close(); }
Запускаем приложение. С помощью мыши изменяем размер формы и закрываем ее. В окне Solution Explorer нажимаем на кнопку(Show All Files) — в папке bin/Debug приложения появился файл applicationSettings.xml (рис. 3.20), в котором записаны размеры формы:
<?xml version="1.0"?> <FormSize xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <height>155</height> <width>250</width> </FormSize>
Добавим теперь обработчик для события Load формы, в котором данные из applicationSettings.xml будут считываться и применяться для установки размеров:
private void Form1_Load(object sender, System.EventArgs e) { //Создаем экземпляр frmSizeSetup класса FormSize: FormSize frmSizeSetup = new FormSize(); //Cоздаем экземпляр xmlser класса XmlSerializer XmlSerializer xmlser = new XmlSerializer(typeof(FormSize)); //Создаем переменную filename, которой присваиваем //название файла applicationSettings.xml в текущей директории string filename = System.Environment.CurrentDirectory + "\\applicationSettings.xml"; //Создаем поток filestream для чтения XML-файла FileStream filestream = new FileStream(filename, FileMode.Open); //Экземпляру frmSizeSetup передаем данные, //полученные в процессе десериализации frmSizeSetup = (FormSize)xmlser.Deserialize(filestream); //Устанавливаем текущие высоту и ширину формы this.Height = frmSizeSetup.height; this.Width = frmSizeSetup.width; //Закрываем поток filestream.Close(); }
В результате получаем следующее — запускаем приложение, изменяем размер формы, закрываем ее. Снова запускаем приложение — форма имеет установленный размер.
На диске, прилагаемом к книге, вы найдете приложение XML-serialization (Code\Glava3\XML-serialization).
Сохранение настроек приложения в реестре операционной системы
Реестр — это база данных, содержащая конфигурационные сведения операционной системы. Основным средством просмотра и редактирования реестра служит специализированная утилита "Редактор реестра". Для ее запуска открываем окно "Выполнить" (Пуск —> Выполнить или используем сочетание клавиш Windows+R) и набираем regedit. Запустившийся редактор содержит шесть корневых разделов (ветвей), краткое описание которых приводится в таблице 3.3.
Разделы | Описание |
---|---|
HKEY_CLASSES_ROOT | Содержится информация о зарегистрированных в Windows типах файлов (что и позволяет открывать их по двойному щелчку), классах и их свойствах |
HKEY_CURRENT_USER | Содержатся настройки оболочки пользователя (например, Рабочего стола, меню "Пуск" и др.). Если на компьютере работает один пользователь и используется обычный вход в Windows, то значения раздела берутся из подраздела HKEY_USERS\.DEFAULT |
HKEY_LOCAL_MACHINE | Содержится информация, относящаяся к компьютеру: драйверы, установленное программное обеспечение и его настройки |
HKEY_USERS | Содержит настройки оболочки Windows для всех пользователей. Именно из этого раздела информация копируется в раздел HKEY_CURRENT_USER. Все изменения в HKCU (сокращенное название раздела HKEY_CURRENT_USER) автоматически переносятся в HKU |
HKEY_CURRENT_CONFIG | Cодержится информация о конфигурации устройств Plug&Play и сведения о конфигурации компьютера с переменным составом аппаратных средств |
HKEY_DYN_DATA | Содержатся динамические данные о состоянии различных устройств, установленных на компьютере пользователя |
Конечным элементом дерева реестра являются ключи или параметры, среди которых можно выделить три основных типа:
- строковые (например, "C:\Program Files");
- двоичные (например. 06 31 B2 8C). Максимальная длина такого ключа 16Кб;
- тип DWORD. Этот тип ключа занимает 4 байта и отображается в шестнадцатеричном и в десятичном виде (например, 0x00000001 (1) — в скобках указано десятичное значение ключа).
Основным классом для работы с реестром (создание новых ключей, их удаление и изменение) в библиотеке .NET Framework является RegistryKey. Описание некоторых методов этого класса приводится в таблице 3.4.
Метод | Описание |
---|---|
CreateSubKey | Создание нового параметра реестра или открытие существующего. Название не чувствительно к регистру |
DeleteSubKey | Удаление существующего параметра |
DeleteSubKeyTree | Удаление существующего раздела и вложенных подразделов |
DeleteValue | Удаление значения существующего параметра |
OpenSubKey | Получение значения парметра только для чтения |
SetValue | Установка значения |
GetValue | Получение значения параметра |
Close | Закрывание параметра и запись его содержимого на постоянной основе |
Вернемся к сохранению настроек приложения — теперь для записи размеров формы мы будем создавать и использовать ключи реестра. Создайте новое Windows-приложение и назовите его RegistrySettings. Подключаем пространство имен для работы с классом RegistryKey:
using Microsoft.Win32;
Снова создаем класс FormSize:
public class FormSize { public int height; public int width; }
В обработчике события Closing формы создаем раздел реестра RegApplication, в котором будут храниться данные:
private void Form1_Closing(object sender, System.ComponentModel.CancelEventArgs e) { FormSize frmSize = new FormSize(); frmSize.height = this.Height; frmSize.width = this.Width; //Открываем раздел RegApplication RegistryKey regkey = Registry.CurrentUser.OpenSubKey ("SOFTWARE\\Microsoft\\RegApplication", true); //Если раздел не обнаружен, создаем его if (regkey ==null) { RegistryKey newregkey = Registry.CurrentUser.OpenSubKey ("SOFTWARE\\Microsoft", true); regkey = newregkey.CreateSubKey("RegApplication"); } //Записываем значения ширины и высоты формы в ключи Height и Width regkey.SetValue("Height", frmSize.height); regkey.SetValue("Width", frmSize.width); }
Запускаем приложение, изменяем размер, закрываем его и добавляем обработчик для события Load формы:
private void Form1_Load(object sender, System.EventArgs e) { FormSize frmSizeSetup = new FormSize(); //Открываем раздел реестра RegistryKey regkey = Registry.CurrentUser.OpenSubKey ("SOFTWARE\\Microsoft\\RegApplication"); //Получаем значения ключей Height и Width if (regkey!=null) { frmSizeSetup.height = Convert.ToInt32(regkey.GetValue("Height")); frmSizeSetup.width = Convert.ToInt32(regkey.GetValue("Width")); //Устанавливаем текущие значения ширины и высоты формы this.Height = frmSizeSetup.height; this.Width = frmSizeSetup.width; } }
При перезапуске приложения его измененный размер сохраняется. В реестре появился раздел RegApplication, в котором и находятся два ключа Height и Width со значениями размеров формы в пикселях (рис. 3.21):
На диске, прилагаемом к книге, вы найдете приложение RegistrySettings (Code\Glava3\ RegistrySettings).
Почтовая программа Ballet
До сих пор мы рассматривали небольшие программки, которые создавали сами. Теперь мы приступим к рассмотрению блоков достаточно большой программы – почтового клиента Ballet. Исходный код содержит подробные комментарии, и вы можете воспроизвести весь проект заново. Он находится на диске, прилагаемом к книге (Code\Glava3\Mail). Возможно, некоторые вопросы покажутся вам незнакомыми; после прочтения всей книги вы сможете вернуться к ним заново — тогда многое станет понятным. Подобно большинству почтовых клиентов, программа Ballet позволяет отправлять, получать, управлять почтовыми сообщениями и вложениями (рис. 3.22 и рис. 3.23). Поддерживается работа нескольких независимых пользователей и почтовых ящиков.
Рассмотрим несколько деталей программы, интересных с технической точки зрения, а потом приступим к разработке программы.
Добавление проектов
При создании большой программы лучше всего работать над ее частями отдельно, помещая их в проекты. В папке Mail (Code\Glava3\Mail) содержатся три проекта в папках Mail 2003, SendMail и MailApplication. В папке Mail2003 содержится код для приема почтовых сообщений, в папке SendMail — код для его отправки, а в папке MailApplication находится интерфейс программы и добавлены проекты Mail из папки Mail 2003 и SendMail из одноименной папки. В терминах Visual Studio .NET любой создаваемый проект представляет собой часть разработки (решения) Solution (рис. 3.22).
При открывании ранее сохраненного проекта мы открывали именно файл NameApplication.sln, представляющий собой решение. Для добавления проектов в решение щелкаем правой кнопкой на его названии и в появившемся меню выбираем Add/New Project (новый проект) или Existing Project (существующий проект) в зависимости от того, что нам нужно (рис. 3.23):
Обратите внимание на то, что само решение MailApplication содержит проект MailApplication. Проекты, объединенные в рамках одного решения, являются связанными, а не внедренными. В этом нетрудно убедиться, переименовав папку одного из проектов или внеся изменения в код: в первом случае в результирующем решении будет ошибка, во втором – изменения затронут листинги и в решении.