Книга: C# для профессионалов. Том II

Пример: SelfPlacingWindow

Пример: SelfPlacingWindow

Проиллюстрируем использование классов реестра с помощью приложения, которое называется SelfPlacingWindow. Этот пример является простым приложением Windows на C#, которое в действительности почти не имеет свойств. Единственное, что можно сделать в этом приложении, это щелкнуть по кнопке, что приведет к появлению стандартного диалогового окна выбора цветов в Window (представляемому классом System.Windows.Forms.ColorDialog), чтобы можно было выбрать цвет который станет фоновым цветом формы

Это приложение обладает одним важным свойством, отсутствующим практически у всех остальных приложений разрабатываемых в этой книге. Если перетащить окно по экрану, изменить его размер, развернуть на весь экран или свернуть его перед выходом из приложения, оно будет запоминать новое положение, а также цвет фона, чтобы в следующий раз при запуске автоматически восстанавливалось последнее выбранное состояние. Оно запоминает эту информацию, так как записывает ее в реестр, когда закрывается. Таким образом, будут продемонстрированы не только сами классы реестра из .NET, но также типичное их использование, которое наверняка захочется скопировать в любое серьезное разрабатываемое коммерческое приложение Window.

Местом, где SelfPlacingWindow хранил свою информацию в реестре, является ключ HKLM/Software/WroxPress/SelfPlacingWindow. HKLM является обычным местом для хранения информации о конфигурации приложений, но отметим, что оно не является специфическим для пользователя. Вероятно, вам понадобится скопировать эту информацию в улей HK_Users, чтобы каждый пользователь имел свой собственный профиль.

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


Если теперь изменить цвет фона и переместить или изменить размер окна приложения SelfPlacingWindow, оно создаст перед завершением ключ HKLM/Software/WroxPress/SelfPlacingWindow и запишет в него свою новую конфигурационную информацию. Можно проверить эту информацию с помощью regedit:


На этом экране можно видеть, что SelfPlacingWindow помещает ряд значений в ключ реестра. 

Значения Red, Green и Blue задают компоненты цветов, которые формируют выбранный цвет фона. О компонентах цвета подробно рассказывается в главе 21. Любой изображаемый цвет в системе может быть полностью описан этими тремя компонентами, каждый из которых представляется числом между 0 и 255 (или 0x00 и 0xff в шестнадцатеричном представлении). Указанные здесь значения задают ярко-зеленый цвет. Существуют также четыре дополнительных значения REG_DWORD, которые представляют положение и размер окна: X и Y являются координатами верхнего левого угла окна на рабочем столе. Width и Height задают размер окна WindowsState является единственным значением, для которого мы использовали строковый тип данных (REG_SZ), и оно может содержать одну из строк normal, maximized или minimized, в зависимости от конечного состояния окна при выходе из приложения.

Если теперь запустить SelfPlacingWindow снова, то оно будет считывать этот ключ реестра и автоматически позиционировать себя соответственно:


В этот раз, когда происходит выход из SelfPlacingWindow, приложение будет перезаписывать предыдущие настройки в реестре новыми значениями, существующими во время выхода из приложения. Чтобы создать код примера, мы создаем проект Windows Forms в Visual Studio.NET и добавляем окно списка и кнопку, используя набор инструментов среды разработчика. Мы изменим имена этих элементов управления соответственно на listBoxMessages и buttonChooseColor. Также необходимо обеспечить использование пространства имен Microsoft.Win32.

using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using Microsoft.Win32;

Нам необходимо добавить одно поле к основному классу Form1, который будет представлять окно диалога выбора цвета.

public class Form1 : System.Windows.Forms.Form {
 /// <summary>
 /// Обязательная переменная проектировщика.
 /// </summary>
 private System.СomponentModel.Container components;
 private System.Windows.Forms.ListBox ListBoxMessages;
 private system.Windows.Forms.Button buttonChooseColor;
 ColorDialog ChooseColorDialog = new ColorDialog();

Довольно много действий происходит в конструкторе Form1:

public Form1() {
 InitializeComponent();
 buttonChooseColor.Click += new EventHandler(OnClickChooseColor);
 try {
  if (ReadSettings() == false)
listBoxMessages.Items.Add("No information in registry");
  else
   listBoxMessages.Items.Add("Information read in from registry");
  StartPosition = FormStartPosition.Manual;
 } catch (Exception e) {
  listBoxMessages.Items.Add("A problem occured reading in data from registry:");
  listBoxMessages.Items.Add(e.Message);
 }
}

В этом конструкторе мы начинаем с создания метода обработки события нажатия пользователем кнопки. Обработчиком является метод с именем OnClickChooseColor (см. ниже). Считывание конфигурационной информации делается с помощью другого метода — ReadSettings(). ReadSettings() возвращает true, если находит информацию в реестре, и false, если не находит (что будет, по-видимому, иметь место, так как приложение выполняется первый раз). Мы помещаем эту часть конструктора в блок try на случай возникновения каких-либо исключений при считывании значений реестра (это может произойти, если вмешался некоторый пользователь и сделал какие-то изменения с помощью regedit).

Инструкция StartPosition = FormStartPosition.Manual; говорит форме взять свою начальную позицию из свойства DeskTopLocation вместо используемого по умолчанию положения в Window (поведение по умолчанию). Возможные значения берутся из перечисления FormStartPosition.

SelfPlacingWindow также является одним из немногих приложений в этой книге, для которого существенно используется добавление кода в метод Dispose(). Напомним, что Dispose() вызывается, когда приложение завершается нормально, так что это идеальное место для сохранения конфигурационной информации в реестре. Это делается с помощью другого метода, который будет написан,— SaveSettings():

/// <summary>
/// Очистить все использованные ресурсы
/// </summary>
public override void Dispose() {
 SaveSettings();
 base.Dispose();
 if(components != null) components.Dispose();
}
SaveSettings()
и ReadSettings() являются методами, которые содержат код для работы с интересующим нас реестром, но прежде чем их рассматривать, необходимо разобраться с обработкой события, возникающего при нажатии пользователем на кнопку. Это предполагает вывод диалогового окна выбора цвета и задание цвета фона в соответствии с выбором пользователя:

void OnClickChooseColor(object Sender, EventArgs e) {
 if (ChooseColorDialog.ShowDialog() == DialogResult.OK)
  BackColor = ChooseColorDialog.Color;
}

Теперь посмотрим, как сохраняются настройки:

void SaveSettings() {
 RegistryKey SoftwareKey = Registry.LocalMachine.OpenSubKey("Software", true);
 RegistryKey WroxKey = SoftwareKey.CreateSubKey("WroxPress");
 RegistryKey SelfPlacingWindowKey = WroxKey.CreateSubKey("SelfPlacingWindowKey");
 SelfPlacingWindowKey.SetValue("BackColor", (object)BackColor.ToKnownColor());
 SelfPlacingWindowKey.SetValue("Red", (object)(int) BackColor.R);
 SelfPlacingWindowKey.SetValue("Green", (object)(int)BackColor.G);
 SelfPlacingWindowKey.SetValue("Blue", (object)(int)Backcolor.В);
 SelfPlacingWindowKey.SetValue("Width", (object)Width);
 SelfPlacingWindowKey.SetValue("Height", (object)Height);
 SelfPlacingWindowKey.SetValue("X", (object)DesktopLocation.X);
 SelfPlacingWindowKey.SetValue("Y", (object)DesktopLocation.Y);
 SelfPlacingWindowKey.SetValue("WindowState", (object)WindowState.ToString());
}

Мы начали с перемещения в реестре, чтобы получить ключ реестра HKLM/Software/WroxPress/SelfPlacingWindow с помощью продемонстрированной выше техники, начиная со статического свойства Registry.LocalMachine, которое представляет улей HKLM:

RegistryKey SoftwareKey = Registry.LocalMachine.OpenSubKey("Software" , true);
RegistryKey WroxKey = SoftwareKey.CreateSubKey("WroxPress");
RegistryKey SelfPlacingWindowKey = WroxKey.CreateSubKey("SelfPlacingWindowKey");

Мы используем метод RegistryKey.OpenSubKey(), а не RegistryKey.CreateSubKey(), позволявший добраться до ключа HKLM/Software. Так происходит вследствие уверенности, что этот ключ уже существует, в противном случае имеется серьезная проблема с компьютером, так как этот ключ содержит настройки для большого объема системного программного обеспечения. Мы также указываем, что нам требуется доступ для записи в этот ключ. Это вызвано тем, что если ключ WroxPress еще не существует, нам нужно будет его создать, что включает запись в родительский ключ.

Следующий ключ для перехода — HKLM/Software/WroxPress, но так как мы не уверены, что ключ уже существует, то используем CreateSubKey() для его автоматического создания, если он не существует. Отметим, что CreateSubKey() автоматически предоставляет доступ для записи к рассматриваемому ключу. Когда мы достигнем HKLM/Software/Wrox. Press/SelfPlacingWindow, то останется просто вызвать метод RegistryKey.SetValue() несколько раз, чтобы создать или задать соответствующие значения. Существуют, однако, некоторые осложнения.

Первое. Можно заметить что мы задействуем пару классов, которые раньше не встречались: свойство DeskTopPosition класса Form указывает позицию верхнего левого угла экрана и имеет тип Point. Рассмотрим структуру Point в главе GDI+. Здесь необходимо знать только, что она содержит два целых числа — X и Y, которые представляют горизонтальную и вертикальную позиции на экране. Мы также используем три свойства члена класса Color: R, G и B. Color представляет цвет, а его свойства задают красный, зеленый и синий компоненты, которые составляют цвет и имеют тип byte. Также применяется свойство Form. WindowState, содержащее перечисление, которое задает текущее состояние окна — minimized, maximized или restored.

Отметим, что при преобразовании типов SetValue() получает два параметра: строку, которая задает имя ключа, и экземпляр System.Object, содержащий значение. SetValue имеет возможность выбора формата для хранения значения, он может сохранить его как REG_SZ, REG_BINARY или REG_DWORD, и он в действительности делает правильный выбор в зависимости от заданного типа данных. Поэтому для WindowsState передается строка и SetValue() определяет, что она должна быть преобразована в REG_SZ. Аналогично для различных позиций и размеров, которые мы передаем, целые значения будут преобразованы в REG_DWORD. Однако компоненты цвета являются более сложными, но мы хотим, чтобы они также хранились как REG_DWORD, потому что они имеют числовые типы. Однако если метод SetValue() видит, что данные имеют тип byte, он будет сохранять их гак строку REG_SZ в реестре. Чтобы избежать этого, преобразуем компоненты цвета в int.

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

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

bool ReadSettings() {
 RegistryKey SoftwareKey = Registry.LocalMachine.OpenSubKey("Software"));
 RegistryKey WroxKey = SoftwareKey.OpenSubKey("WroxPress");
 if (WroxKey == null) return false;
 RegistryKey SelfPlacingWindowKey = WroxKey.OpenSubKey("SelfPlacingWindow");
 if (SelfPlacingWindowKey == null) return false;
 else
listBoxMessages.Items.Add("Successfully opened key " + SelfPlacingWindowKey.ToString());
 int RedComponent = (int)SelfPlacingWindowKey.GetValue("Red");
 int GreenComponent = (int)SelfPlacingWindowKey.GetValue("Green");
 int BlueComponent = (int)SelfPlacingWindowKey.GetValue("Blue");
 BackColor = Color.FromArgb(RedComponent, GreenComponent, BlueComponent);
 listBoxMessages.Items.Add("Background color: " + BackColor.Name);
 int X = (int(SelfPlacingWindowKey.GetValue("X");
 int Y = (int)SelfPlacingWindowKey.GetValue("Y");
 DesktopLocation = new Point(X, Y);
 listBoxMessages.Items.Add("Desktop location: " + DesktopLocation.ToString());
 Height = (int)SelfPlacingWindowKey.GetValue("Height");
 Width = (int)SelfPlacingWindowKey.GetValue("Width");
 listBoxMessages.Items.Add("Size: " + new Size(Width, Height).ToString());
 string InitialWindowState = (string)SelfPlacingWindowKey.GetValue("WindowState");
 listBoxMessages.Items.Add("Window State: " + InitialWindowState);
 WindowState =
  (FormWindowState)FormWindowState.Parse(WindowState.GetType() , InitialWindowState)
 return true;
}

В ReadSettings() мы должны сначала перейти в ключ реестра HKLM/Software/WroxPress/SelfPlacingWindow. При этом, однако, мы надеемся найти ключ, чтобы его можно было прочитать. Если его нет, то, вероятно, пример выполняется в первый раз. В этом случае мы хотим прервать чтение ключей, и, конечно, не желаем создавать какие-либо ключи. Теперь мы все время используем метод RegistryKey.OpenSubkey(). Если на каком-то этапе OpenSubkey() возвращает ссылку null, то мы знаем, что ключ реестра отсутствует, и можем вернуть значение false в вызывающий код.

В реальности для считывания ключей используется метод RegistryKey.GetValue(), который определен как возвращающий объектную ссылку, это означает, что такой метод может на самом деле вернуть экземпляр практически любого класса, который он выберет подобно SetValue(), он возвращает класс объекта, соответствующий типу данных, которые он найдет в ключе. Поэтому можно предполагать, что ключ REG_SZ будет выдан как строка, а другие ключи — как int. Мы также преобразуем соответственно возвращаемую из SetValue() ссылку. При возникновении исключения, если кто-то делал какие-то манипуляции с реестром и исказил типы данных, наше преобразование породит исключение, которое будет перехватываться обработчиком в конструкторе Form1.

Остальная часть кода использует еще один тип данных, структуру Size, выглядящую пока незнакомой, потому что она будет рассматриваться только в главе GDI+. Структура Size аналогична Point, но используется для представления размеров, а не координат. Она имеет два свойства члена — Width и Height, и мы используем структуру Size в данном случае просто как удобный способ представления размера формы для вывода в поле списка.

Оглавление книги


Генерация: 2.109. Запросов К БД/Cache: 3 / 1
поделиться
Вверх Вниз