Создание Windows-приложений на основе Visual C#

Работа с элементами управления (продолжение)

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

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

Операция Drag-and-Drop

Операция Drag-and-Drop предназначена для перемещения и копирования объектов при помощи мыши. Выделив фрагмент текста в Microsoft Word, его можно перетащить в другой документ или в другую позицию текущего документа, нажав и затем отпустив левую кнопку мыши (рис. 3.1).

(рис 3.1) Перетаскивание выделенного фрагмента текста

Создайте новое приложение и назовите его DragAndDrop. Расположите на форме два элемента TextBox и один RichTextBox, установив следующие значения свойств:

textBox1, свойствоЗначение
Name textBox1
Location 48; 16
Size 184; 20
Text Текст для перетаскивания
textBox2, свойствоЗначение
Name textBox2
AllowDrop True
Location 48; 64
Size 184; 20
Text Сюда можно поместить текст
richTextBox1, свойствоЗначение
Name richTextBox1
AllowDrop True
Dock Bottom
Location 0; 130
Text Текст для Microsoft Word

Значение True свойства AllowDrop разрешает размещение текстового фрагмента в данном элементе. Выделяем элемент textBox1, в окне Properties переключаемся на его события и дважды щелкаем в поле MouseDown. В обработчике этого события вызываем метод DoDragDrop:

private void textBox1_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e)
{
  textBox1.DoDragDrop(textBox1.Text, DragDropEffects.Copy);
}

В качестве второго параметра метода мы передаем одно из значений перечисления DragDropEffects — здесь мы выбрали копирование текста Copy. Итак, при нажатой кнопке мыши содержимое текста первого текстового поля будет скопировано. В окне Properties второго элемента TextBox дважды щелкаем в поле события DragEnter. В обработчике этого события будем проверять соответствие представляемых данных формату String:

private void textBox2_DragEnter(object sender, System.Windows.Forms.DragEventArgs e)
    {
      if (e.Data.GetDataPresent(DataFormats.StringFormat)) 
        e.Effect = DragDropEffects.Copy;
      else
        e.Effect = DragDropEffects.None;
    }

И наконец, при отпускании кнопки мыши в поле этого же элемента будет выводиться скопированный текст:

private void textBox2_DragDrop(object sender, System.Windows.Forms.DragEventArgs e)
 {
   textBox2.Text = e.Data.GetData(DataFormats.StringFormat).ToString();
 }

Для реализации операции Drag-and-Drop в списке событий окна Properties элемента RichTextBox нет нужных нам событий DragDrop и DragEnter, поэтому в области Windows Form Designer generated code нам придется объявить обработчиков для этих событий:

// 
// richTextBox1
//
…
this.richTextBox1.DragDrop += new System.Windows.Forms.DragEventHandler
(this.richTextBox1_DragDrop);
this.richTextBox1.DragEnter += new System.Windows.Forms.DragEventHandle
r(this.richTextBox1_DragEnter);

Делаем проверку на соответствие формату String:

private void richTextBox1_DragEnter(object sender, 
   System.Windows.Forms.DragEventArgs e)
 {
   if (e.Data.GetDataPresent(DataFormats.Text)) 
     e.Effect = DragDropEffects.Copy;
   else
     e.Effect = DragDropEffects.None;
 }

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

private void richTextBox1_DragDrop(object sender, 
   System.Windows.Forms.DragEventArgs e)
 {
   int i;
   String s;

   // Определяем начальную позицию для текста
   i = richTextBox1.SelectionStart;
   s = richTextBox1.Text.Substring(i);
   richTextBox1.Text = richTextBox1.Text.Substring(0,i);

   // Перетаскиваем текст 
   richTextBox1.Text = richTextBox1.Text + 
  e.Data.GetData(DataFormats.Text).ToString();
   richTextBox1.Text = richTextBox1.Text + s;
 }

Запускаем приложение. Теперь можно перетаскивать текст из верхнего текстового поля в нижнее, а в элемент RichTextBox — даже фрагмент текста из Microsoft Word (рис. 3.2):

(рис 3.2) Приложение DragAndDrop, перетаскивание фрагмента текста из Microsoft Word

На диске, прилагаемом к книге, вы найдете приложение DragAndDrop (Code\Glava3\ DragAndDrop).

Добавление элементов управления в режиме работы приложения. Элементы управления CheckBox, GroupBox и RadioButton

При размещении на форме элемента управления в режиме дизайна, среда создает код в области Windows Form Designer generated code, описывающий этот элемент. Если мы назначим в обработчике заданного элемента управления генерацию аналогичного кода, то в запущенном приложении можно будет добавлять на форму другие элементы, активизируя этот обработчик. Для добавления элементов управления используется объект ControlsCollection, содержащий ряд методов (см. таблицу 3.1). Под коллекцией элементов понимается их упорядоченная последовательность.

Некоторые методы ControlsCollection
МетодОписание
Add Добавление элемента в коллекцию
AddRange Добавление массива элементов
Clear Удаление всех элементов из коллекции
Remove Удаление элемента из коллекции
RemoveAt Удаление элемента по заданному индексу
Count Общее число элементов в коллекции

Рассмотрим на практике добавление элементов управления. Создайте новое приложение и назовите его RegistrationForm. Располагаем на форме три надписи, два текстовых поля, кнопку, элементы CheckBox и GroupBox (рис. 3.3):

(рис 3.3) Приложение RegistrationForm. Расположение элементов на форме в режиме дизайна

Устанавливаем следующие значения свойств формы и элементов управления:

Form1, форма, свойствоЗначение
Size 392; 320
Text Регистрация программы
label1, свойствоЗначение
Location 32; 8
Size 224; 24
Text Выберите тип регистрации
label2, свойствоЗначение
Location 16; 32
Size 48; 23
Text Name
label3, свойствоЗначение
Location 16; 64
Size 40; 23
Text PIN
Button1, свойствоЗначение
Location 80; 248
Size 144; 23
Text Регистрация
TextBox1, свойствоЗначение
Location 96; 32
Size 184; 20
Text
TextBox2, свойствоЗначение
Location 96; 64
Size 184; 20
Text
CheckBox1, свойствоЗначение
Location 40; 40
Size 232; 24
Text Расширенные возможности
GroupBox1, свойствоЗначение
Location 16; 80
Size 344; 144
Text Введите регистрационые данные

Элемент CheckBox обычно применяется для выбора отложенного действия, но в данном случае при его выборе немедленно будет появляться дополнительное текстовое поле и надпись. Щелкаем дважды на этом элементе в режиме дизайна — при этом создается событие CheckedChanged:

private void checkBox1_CheckedChanged(object sender, System.EventArgs e)
 {
   //Создаем новый экземпляр lbl класса Label:
   Label lbl = new Label();
   //Определяем расположение  надписи — свойство Location
   lbl.Location = new System.Drawing.Point(16, 96);
   //Устанавливаем размер надписи
   lbl.Size = new System.Drawing.Size(32, 23);
   //Задаем имя:
   lbl.Name = "labelll";
   //Определяем порядок переключения при нажатии клавиши Tab
   lbl.TabIndex = 2;
   //Устнаавливаем текст надписи на форме
   lbl.Text = "PIN2";
   //Добавляем элемент в коллекцию, вызывая метод Add
   groupBox1.Controls.Add(lbl);


   TextBox txt = new TextBox();
   txt.Location = new System.Drawing.Point(96, 96);
   txt.Size = new System.Drawing.Size(184, 20);
   txt.Name = "textboxx";
   txt.TabIndex = 1;
   txt.Text = "";
   groupBox1.Controls.Add(txt);
 
 }

Запускаем приложение. При выборе пункта "Расширенные возможности" на форме появляется третье текстовое поле. Для определения параметров добавляемого элемента, таких как размер и расположение, лучше всего добавить элемент в режиме дизайна формы, скопировать нужные параметры из области Windows Form Designer generated code, а затем удалить его.

Добавим на форму два элемента RadioButton (переключателя) — при последовательном их выборе дополнительные текстовое поле и надпись будут появляться или исчезать. Устанавливаем значения свойства Text этим элементам "Полная" и "Ограниченная". Дважды щелкаем на каждый из переключателей, переходя в их код. В обработчике первого элемента RadioButton вставляем скопированный код из обработчика чекбокса. При выборе второго переключателя вся группа элементов, содержащаяся в GroupBox, будет удалена, а затем в новую группу добавятся два текстовых поля и две надписи:

private void radioButton2_CheckedChanged(object sender, System.EventArgs e)
 {
   //Удаляем все элементы из коллекции
   groupBox1.Controls.Clear();
   
   //Добавляем первую надпись
   Label lbl1 = new Label();
   lbl1.Location = new System.Drawing.Point(16, 32);
   lbl1.Name = "labelfirst";
   lbl1.Size = new System.Drawing.Size(48, 23);
   lbl1.TabIndex = 4;
   lbl1.Text = "Name";
   groupBox1.Controls.Add(lbl1);
   
   //Добавляем вторую надпись
   Label lbl2 = new Label();
   lbl2.Location = new System.Drawing.Point(16, 64);
   lbl2.Name = "labelsecond";
   lbl2.Size = new System.Drawing.Size(40, 23);
   lbl2.TabIndex = 3;
   lbl2.Text = "PIN";
   groupBox1.Controls.Add(lbl2);

   //Добавляем первое текстовое поле
   TextBox txt1 = new TextBox();
   txt1.Location = new System.Drawing.Point(96, 32);
   txt1.Name = "textBox1";
   txt1.Size = new System.Drawing.Size(184, 20);
   txt1.TabIndex = 0;
   txt1.Text = "";
   groupBox1.Controls.Add(txt1);

   //Добавляем  второе  текстовое поле
   TextBox txt2 = new TextBox();
   txt2.Location = new System.Drawing.Point(96, 64);
   txt2.Name = "textBox2";
   txt2.Size = new System.Drawing.Size(184, 20);
   txt2.TabIndex = 1;
   txt2.Text = "";
   groupBox1.Controls.Add(txt2);
 }

Запускаем приложение. При выборе переключателя cо значением свойства Text "Полная" снова появляются дополнительные элементы (рис. 3.4):

(рис 3.4) Результат запуска приложения RegistrationForm

На диске, прилагаемом к книге, вы найдете приложение RegistrationForm (Code\Glava3\ RegistrationForm).

Удаление заданного элемента в режиме работы приложения

В рассмотренном выше примере мы удаляли всю коллекцию элементов. Рассмотрим более сложный пример — удаление добавленного элемента по щелчку правой кнопкой мыши на нем. Создайте новое приложение и назовите его AddRemoveControls. Устанавливаем свойству AutoScroll формы значение True для возможности прокрутки формы. Добавляем на форму кнопку и помещаем ее в верхний левый угол формы. В поле свойства Text кнопки вводим Clone. Переходим в обработчик кнопки:

private void button1_Click(object sender, System.EventArgs e)
{
  //Создаем экземпляр btn класса Button
  Button btn = new Button();
  //Определяем количество элементов управления
  Control prev = (Control)this.Controls[this.Controls.Count-1];
  //Устанавливаем позицию добавляемых кнопок
  int x1 = prev.Location.X;
  int y1 = prev.Location.Y;
  int height = prev.Height;
  int width = prev.Width;
  btn.Location = new Point(x1+ width+5, y1 + height +5);
  btn.Width = prev.Width;
  btn.Height = prev.Height;
  //Добавляем событие для новой кнопки и обработчик button1_Click
  btn.Click+= new EventHandler(button1_Click);
  //Устанавливаем свойство Text кнопки
  btn.Text = "Clone";
  //Добавляем экземпляр в коллекцию
  this.Controls.Add(btn);
  //Определяем обработчик для события MouseUp экземпляра кнопки btn
  btn.MouseUp+= new MouseEventHandler(button1_MouseUp);
}

Переключаемся в режим дизайна формы, выделяем кнопку, в окне Properties нажимаем на кнопку событий(Events) и дважды щелкаем в поле события MouseUp:

private void button1_MouseUp(object sender, System.Windows.Forms.MouseEventArgs e)
{
  if(e.Button==MouseButtons.Right)
  {
 //Удаляем данную кнопку
 this.Controls.Remove((Control)sender);
  }
}

Запускаем приложение. При щелчке левой кнопкой мыши на любой из кнопок добавляется еще одна, а при щелчке правой кнопкой мыши на заданной кнопке она исчезает (рис. 3.5):

(рис 3.5) Результат запуска приложения AddRemoveControls

На диске, прилагаемом к книге, вы найдете приложение AddRemoveControls (Code\Glava3\ AddRemoveControls).

Добавление пунктов контекстного меню в режиме запуска приложения. Элемент управления ComboBox

В зависимости от различных событий, происходящих на форме, содержание контекстного меню может меняться. Создайте новое приложение и назовите его MenuRunTime. Добавляем на форму элемент управления GroupBox (контейнер) и размещаем внутри него две надписи, текстовое поле, кнопку, ComboBox (выпадающий список) (см. рис. 3.6).

(рис 3.6) Приложение MenuRunTime в режиме дизайна

Устанавливаем следующие свойства кнопки, текстового поля и выпадающего списка:

textBox1, свойствоЗначение
Name txtMenuText
Text
comboBox1, свойствоЗначение
Name cmbShortCuts
Text
button1, свойствоЗначение
Name btnAdd
Text Добавить

Добавляем на форму элементы управления ContextMenu и ColorDialog. Свойству СontextMenu формы Form1 устанавливаем значение добавленного контекстного меню — сontextMenu1. Вводим пункты контекстного меню:

NameTextShortcut
mnuChangeColor Изменить цвет CtrlG
mnuExit Выход AltF4

В обработчике пункта меню mnuChangeColor вызываем диалог colorDialog1 и присваиваем выбранное значение цвета фоновому цвету формы:

private void mnuChangeColor_Click(object sender, System.EventArgs e)
{
  if(colorDialog1.ShowDialog()==DialogResult.OK)
  {
 this.BackColor =colorDialog1.Color;
  }
}

В обработчике пункта меню "Выход" просто закрываем форму:

private void mnuExit_Click(object sender, System.EventArgs e)
{
  this.Close();
}

Элемент ComboBox обычно заполняется значениями в режиме дизайна — для этого используется его свойство Items. Однако в нашем примере при загрузке формы мы заполним его всеми значениями сочетаний клавиш, поддерживаемых средой CLR:

private void Form1_Load(object sender, System.EventArgs e)
{
  object[] sc = new object[Enum.GetValues(typeof (Shortcut)).Length];
  Enum.GetValues(typeof(Shortcut)).CopyTo(sc,0);
  cmbShortCuts.Items.AddRange(sc);
}

В обработчике кнопки btnAdd будет создаваться новый пункт меню и добавляться в контекстное меню сontextMenu1:

private void btnAdd_Click(object sender, System.EventArgs e)
{
   //Если значение текстового поля пустое, выводим сообщение
   if(txtMenuText.Text=="")
   {
     //Текст сообщения
     MessageBox.Show("Введите текст для пункта меню");
     return;
   }
    //Если не выбрано значение сочетания клавиш, выводим сообщение
    if(cmbShortCuts.SelectedItem==null)
   {
      //Текст сообщения
     MessageBox.Show("Выберите сочетание клавиш");
     return;

   }
   //Создаем новый экземпляр mnu класса пунктов  меню MenuItem
   MenuItem mnu = new MenuItem();
   //Устанавливаем в качестве текста пункта значение, введенное в txtMenuText
   mnu.Text = txtMenuText.Text;
   //Устанавливаем в качестве сочетания клавиш данного пункта 
   //выбранное значение из cmbShortCuts
   mnu.Shortcut=(Shortcut)cmbShortCuts.SelectedItem;
   //Добавляем пункт в контекстное меню contextMenu1
   contextMenu1.MenuItems.Add(mnu);
   //Определяем обработчик для события Click экземпляра  mnu
   mnu.Click += new System.EventHandler(this.NewmnuChangeColor_Click);
    }

В обработчике нового пункта снова будем вызывать диалог colorDialog1:

//Обработчик события Click экземпляра mnu
private void NewmnuChangeColor_Click(object sender, System.EventArgs e)
{
  if(colorDialog1.ShowDialog()==DialogResult.OK)
  {
 this.BackColor =colorDialog1.Color;
  }
}

Запускаем приложение. Цвет формы можно изменить, выбрав соответствующий пункт меню или используя сочетание клавиш Ctrl+G (рис. 3.7). После введения текста пункта, выбора ярлыка и нажатия кнопки "Добавить" новый пункт доступен в меню (рис. 3.8).

(рис 3.8) Контекстное меню приложения MenuRunTime(рис 3.7) Новый пункт "Снова изменить цвет" в контекстном меню

Добавление пунктов главного меню в режиме работы приложения ничем не отличается от рассмотренного – если бы мы поместили на форму главное меню, предпоследняя строчка обработчика кнопки btnAdd приняла бы вид:

//Добавляем пункт в главное меню mainMenu1
mainMenu1.MenuItems.Add(mnu);

На диске, прилагаемом к книге, вы найдете приложение MenuRunTime (Code\Glava3\MenuRunTime).

Проверка вводимых значений. События KeyPress и Validating элемента управления TextBox

При внесении значений параметров пользователем или заполнении регистрационной формы требуется проверять вводимый текст по заданным критериям. Например, регистрационный номер не должен содержать букв. Рассмотрим проверку, которую можно осуществлять, используя встроенные события текстового поля. Скопируйте папку приложения RegistrationForm и дайте ей новое название — ValidatingInput. Запускаем проект. Текстовым полям, находящимся напротив надписей Name и PIN, задаем названия (значения свойства Name) — txtName и txtPIN соответственно. Располагаем на форме новую надпись lbloutput – на нее будут выводиться сообщения об ошибках, поэтому значение свойства Text оставляем пустым. Выделяем поочередно текстовые поля и в окне Properties создаем обработчиков события KeyPress, возникающего при нажатии любой клавиши в поле. Для элемента txtName недопустимыми значениями будут цифры:

private void txtName_KeyPress(object sender, System.Windows.Forms.KeyPressEventArgs e)
    {
   if (char.IsDigit(e.KeyChar) )
   {
  e.Handled = true;
     lbloutput.Text = "Поле Name не может содержать цифры";
   }
   
 }

Для элемента txtPIN, наоборот, недопустимыми значениями будут буквы:

private void txtPIN_KeyPress(object sender, System.Windows.Forms.KeyPressEventArgs e)
 {
   if (!char.IsDigit(e.KeyChar) )
   {
     e.Handled = true;
     lbloutput.Text ="Поле PIN не может содержать буквы";
   }

    }

Запускаем приложение. При попытке ввести недопустимое значение в одно из полей появляется сообщение, а клавиатура блокируется. Даже стандартная кнопка закрытия формы не работает, пока не будут внесены исправления.

Для текстового поля, появляющегося при установке галочки в чекбоксе "Расширенные возможности", необходимо вручную определить событие KeyPress:

private void checkBox1_CheckedChanged(object sender, System.EventArgs e)
{
  …
  txt.KeyPress+= new System.Windows.Forms.KeyPressEventHandler(this.txtPIN_KeyPress);
}

Запускаем приложение. Теперь проверяются значения и в появляющемся поле PIN2 (рис. 3.9).

(рис 3.9) Проверка значений поля PIN2. Текст сообщения, появляющегося при ошибке, был изменен

Событие KeyPress блокирует часть клавиатуры. Другим способом проверки является событие Validating, позволяющее работать с клавиатурой, но блокирующее другие действия пользователя. Закомментируем обработчик txtPIN_KeyPress, переключимся в режим дизайна формы и в окне Properties элемента txtPIN создадим обработчик события Validating:

private void txtPIN_Validating(object sender, System.ComponentModel.CancelEventArgs e)
 {
   if(txtPIN.Text =="")
   {
     e.Cancel=false;
   }
   else
   {
     try
     {
    double.Parse(txtPIN.Text);
    e.Cancel = false;
         
     }
     catch
     {
    e.Cancel = true;
       lbloutput.Text ="Поле PIN не может содержать буквы";
     }
   }
    }

Для проверки введенное значение преобразуется к типу double — текст сгенерирует исключение. Запускаем приложение. При переключении фокуса ввода или нажатии на кнопку "регистрация" происходит событие Validating.

На диске, прилагаемом к книге, вы найдете приложение ValidatingInput (Code\Glava3\ ValidatingInput).

Проверка вводимых значений. Элемент управления ErrorProvider

Элемент управления ErrorProvider удобно применять, когда нужно выводить небольшую иконку в случае ошибки ввода. Скопируйте папку RegistrationForm и назовите ее ErrorProvider. Запускаем проект, в режиме дизайна из окна ToolBox перетаскиваем на форму элемент управления ErrorProvider. Переходим в код формы. Изменим обработчиков txtName_KeyPress и txtPIN_KeyPress следующим образом:

private void txtName_KeyPress(object sender, System.Windows.Forms.KeyPressEventArgs e)
 {
   if (char.IsDigit(e.KeyChar) )
   {
     errorProvider1.SetError(txtName, "Must be letter");
     lbloutput.Text = "Поле Name не может содержать цифры";
   }
   
    }

 private void txtPIN_KeyPress(object sender, System.Windows.Forms.KeyPressEventArgs e)
 {
   if (!char.IsDigit(e.KeyChar) )
   {
  errorProvider1.SetError(txtPIN, "Must be number");
  lbloutput.Text ="Поля PIN и PIN2 не могут содержать буквы";
   }

 }

Вторым параметром в методе SetError передается строка с описанием ошибки, которая может быть выведена на форму. Мы воспользуемся, однако, выводом сообщения в надписи lbloutput. Запускаем приложение. При ошибке появляется мигающая иконка уведомления (рис. 3.10):

(рис 3.10) Иконка уведомления элемента ErrorProvider

Некоторые свойства элемента ErrorProvider, отвечающие за внешний вид иконки, приводятся в таблице 3.2.

Свойства ErrorProvider
СвойствоОписаниеЗначение по умолчанию
Blinkrate Частота мерцания в миллисекундах 250
BlinkStyle Стиль появления иконки. Возможны следующие варианты: BlinkIfDifferentError – иконка появляется при ошибке, мерцает несколько раз и останавливается;AlwaysBlink – при ошибке иконка мерцает постоянно;NeverBlink – иконка появляется, но не мерцает BlinkIfDifferentError
Icon Изображение иконки. Можно использовать другие файлы иконок (.ico) (Icon)

На диске, прилагаемом к книге, вы найдете приложение ErrorProvider (Code\Glava3\ ErrorProvider).

Создание пользовательских (композитных) элементов управления. Элемент управления NumericUpDown

Одинаковая группа элементов с привязанными обработчиками может требоваться в нескольких частях большого приложения или даже нескольких приложений. Например, программы Microsoft Word и Excel содержат много одинаковых связанных элементов — панели инструментов, окна настроек, группы меню. Среда Visual Studio .NET предоставляет возможность создания функциональных блоков, состоящих из многих элементов; применение этих блоков позволяет значительно ускорить разработку приложений. Создаем новый проект в Visual Studio .NET — на этот раз выбираем шаблон Windows Control Library (рис. 3.11).

(рис 3.11) Проект UserInput, шаблон проекта — Windows Control Library

Появляется форма без границ, представляющая собой основу, на которой будут располагаться элементы. В принципе, можно разрабатывать функциональность и проверять код, компилируя проект при помощи пункта меню Build (Ctrl+Shift+B). Однако при этом мы не увидим результатов работы композитного элемента, пока не добавим его на другую форму. Поэтому на время разработки переделаем проект в Windows-приложение, а потом, когда все будет готово, вернем ему исходный вид. При попытке запустить приложение появляется сообщение "A project with an Output Type of Class Library cannot be started directly" (Проект с выходным типом Class Library (Библиотека классов) не может быть запущен непосредственно). В окне Solution Explorer щелкаем правой кнопкой на имени проекта UserInput и в появившемся контекстном меню выбираем Properties. В окне UserInput Property Pages изменяем значение свойства OutputType на Windows Application. Снова запускаем приложение. Появляется ошибка — приложение не содержит точки входа:

Program 'D:\Uchebnik\Code\Glava3\UserInput\obj\Debug
\UserInput.exe' does not have an entry point defined

Добавляем метод Main в класс формы:

[STAThread]
 static void Main() 
 {
   Application.Run(new UserControl1());
 }

Снова запускаем приложение — появляются две ошибки:

1.D:\Uchebnik\Code\Glava3\UserInput\UserControl1.cs(44): The best overloaded 
method match for'System.Windows.Forms.Application.Run(System.Windows.Forms.Form)' has
some invalid arguments

2.D:\Uchebnik\Code\Glava3\UserInput\UserControl1.cs(44): 
Argument '1': cannot convert from 'UserInput.UserControl1' 
to 'System.Windows.Forms.Form'

Класс UserControl1 наследует от класса UserControl:

public class UserControl1 : System.Windows.Forms.UserControl

Обычный класс Windows-приложения наследует от класса Form:

public class Form1 : System.Windows.Forms.Form

Закомментируем наследование этого класса (не удалим!) и добавим наследование от класса Form:

public class UserControl1 : System.Windows.Forms.Form

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

Займемся теперь созданием функциональности. Добавляем на форму три надписи, текстовое поле, ErrorProvider и элемент управления NumericUpDown (рис. 3.12):

(рис 3.12) Проект UserInput, расположение элементов управления на форме

Две надписи будут статичными, а на третью будут выводиться сообщения при ошибках. Установим свойству Name этой надписи значение lbloutput. Устанавливаем следующие значения текстового поля, элементов ErrorProvider и NumericUpDown:

textBox1, свойствоЗначение
Name txtName
Text
numericUpDown1, свойствоЗначение
Name numUDAge
Maximum 100
Minimum 1
Value 25
errorProvider1, свойствоЗначение
BlinkStyle AlwaysBlink
Icon Code\Glava3\UserInput\Icon\none.ico

Проверять ввод значений будем в текстовом поле и элементе NumericUpDown. В окне Properties создаем обработчиков событий Validated элементов:

private void txtName_Validated(object sender, System.EventArgs e)
 {
   if(nameValid())
   {
     // Все правильно, удаляем сообщение с надписи
     errorProvider1.SetError(txtName, "");
   }
   else
   {
     //Поле не заполнено — выводим сообщение
     errorProvider1.SetError(txtName, "Name is required.");
     lbloutput.Text = "Введите имя!";
   }
 
 }

 private void numUDAge_Validated(object sender, System.EventArgs e)
 {
   if (ageLess())
   {
  // Введенное значение  меньше 25
     errorProvider1.SetError(numUDAge, "Age not old enough");
     lbloutput.Text = "Введите значение, большее или равное  25";
   }
   else if (ageMore())
   {
     /// Введенное значение  больше 25
     errorProvider1.SetError(numUDAge, "Age is too old");
     lbloutput.Text = "Введите значение, меньшее или равное  65";
   }
   else 
   {
     // Все правильно, удаляем сообщение с надписи
     errorProvider1.SetError(numUDAge, "");
   }
    
 }

Осталось добавить методы, в которых проверяются заданные значения:

private bool nameValid() 
 {
   // Проверяем заполнение текствого поля
   return ( txtName.Text.Length > 0);
 }

 private bool ageLess() 
 {
 //Возраст меньше 25
   return (numUDAge.Value < 25);
 }

 private bool ageMore() 
 {
   //Возраст больше 65
   return (numUDAge.Value > 65 );
 }

Запускаем приложение. При ошибках иконка мигает беспрерывно, в случае ее исправления сообщение исчезает (рис. 3.13):

(рис 3.13) Готовое приложение UserInput

Преобразуем теперь проект в композитный элемент, скомпилируем его в режиме Build (Ctrl+Shift+B) и закроем.

На диске, прилагаемом к книге, вы найдете приложение UserInput (Code\Glava3\UserInput).

Добавление пользовательских (композитных) элементов управления

После создания композитного элемента его можно добавлять в обычные приложения. Создайте новое Windows-приложение и назовите его TestUserElement. В окне Toolbox щелкаем правой кнопкой на закладке Windows Forms и выбираем пункт Add/Remove Items… В окне Customize Toolbox на вкладке .NET Framework Components нажимаем кнопку Browse и выбираем файл UserInput.dll из папки bin/Debug проекта UserInput. В результате в окне компонент появляется элемент UserControl1, принадлежащий пространству имен UserInput (рис. 3.14):

(рис 3.14) Компонент UserControl1

Закрываем окно Customize Toolbox — в окне ToolBox создан элемент управления UserControl1, который, как и обычный элемент, мы можем перетаскивать на форму, переименовывать и копировать (рис. 3.15).

(рис 3.15) Для добавления элемента UserControl1 просто перетаскиваем его на форму

Для работы композитного элемента уже не требуется никакого кода — он представляет собой полностью автономный функциональный блок (рис. 3.16):

(рис 3.16) Приложение TestUserElement

Можно создавать пользовательские элементы управления непосредственно в текущем проекте — для этого в окне Solution Explorer щелкаем на названии проекта TestUserElement и в появившемся меню выбираем Add/Add User Control.

На диске, прилагаемом к книге, вы найдете приложение TestUserElement (Code\Glava3\TestUserElement).

Запуск приложения в области уведомлений. Элемент управления NotifyIcon

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

(рис 3.17) Приложения в области уведомления

Создайте новое приложение и назовите его SystemTray. Перетаскиваем на форму из окна ToolBox элементы управления ContextMenu и NotifyIcon. Элемент управления NotifyIcon и представляет собой отображение запущенного приложения в области задач. Добавляем пункты контекстного меню и устанавливаем следующие свойства элемента NotifyIcon:

contextMenu1,
свойство Name Text
mnuShow Показать
mnuHide Скрыть
notifyIcon1, свойствоЗначение
СontextMenu contextMenu1
Icon Code\Glava3\SystemTray\Icon\ eventlogWarn.ico
Text Область уведомлений

Изображение, используемое в качестве иконки (свойство Icon) элемента NotifyIcon, будет выводиться в область уведомлений. Значение свойства Text представляет собой текст всплывающей подсказки, появляющейся при наведении курсора на иконку приложения. Добавляем обработчик пункта меню mnuShow:

private void mnuShow_Click(object sender, System.EventArgs e)
 {
   //Включаем отображения приложения на панели задач при запуске
   this.ShowInTaskbar = true;
   //Показываем форму
   this.Show();
   //Отключаем доступность пункта меню mnuShow
   mnuShow.Enabled = false;
   //Включаем доступность пункта меню mnuHide
   mnuHide.Enabled = true;
   //Переменной Hidden устанавливаем значение false
   
 }

Обработчик пункта меню mnuHide изменяет эти значения на обратные:

private void mnuHide_Click(object sender, System.EventArgs e)
 {
   this.ShowInTaskbar = false;
   this.Hide();
   mnuShow.Enabled = true;
   mnuHide.Enabled = false;
   
 }

В конструкторе формы скрываем видимость приложения на панели задач при запуске:

public Form1()
 {
   InitializeComponent();
   this.ShowInTaskbar = false;
 }

Переключаемся в режим дизайна, в окне Properties элемента управления NotifyIcon переключаемся на события и дважды щелкаем в поле события DoubleClick:

private void notifyIcon1_DoubleClick(object sender, System.EventArgs e)
{
  mnuShow_Click(this, new EventArgs());
}

В результате обработчиком события notifyIcon1_DoubleClick будет обработчик mnuShow_Click. Запускаем приложение. При сворачивании приложение исчезает с панели задач, а развернуть его можно, щелкнув дважды на иконке в области уведомлений или выбрав пункт "Показать в контекстном меню" (рис. 3.18 и рис. 3.19):

(рис 3.19) При наведении курсора на иконку появляется подсказка — "Область уведомлений"(рис 3.18) Контекстное меню

На диске, прилагаемом к книге, вы найдете приложение SystemTray (Code\Glava3\SystemTray).

Сохранение настроек приложения. 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>
(рис 3.20) Файл applicationSettings.xml в окне Solution Explorer

Добавим теперь обработчик для события 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.

Основные разделы реестра операционной системы Windows
РазделыОписание
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одержится информация о конфигурации устройств PlugPlay и сведения о конфигурации компьютера с переменным составом аппаратных средств
HKEY_DYN_DATA Содержатся динамические данные о состоянии различных устройств, установленных на компьютере пользователя

Конечным элементом дерева реестра являются ключи или параметры, среди которых можно выделить три основных типа:

  • строковые (например, "C:\Program Files");
  • двоичные (например. 06 31 B2 8C). Максимальная длина такого ключа 16Кб;
  • тип DWORD. Этот тип ключа занимает 4 байта и отображается в шестнадцатеричном и в десятичном виде (например, 0x00000001 (1) — в скобках указано десятичное значение ключа).
  • Основным классом для работы с реестром (создание новых ключей, их удаление и изменение) в библиотеке .NET Framework является RegistryKey. Описание некоторых методов этого класса приводится в таблице 3.4.

    Некоторые методы класса RegistryKey
    МетодОписание
    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):

    (рис 3.21) Раздел RegApplication с двоичными ключами Height и Width

    На диске, прилагаемом к книге, вы найдете приложение RegistrySettings (Code\Glava3\ RegistrySettings).

    Почтовая программа Ballet

    До сих пор мы рассматривали небольшие программки, которые создавали сами. Теперь мы приступим к рассмотрению блоков достаточно большой программы – почтового клиента Ballet. Исходный код содержит подробные комментарии, и вы можете воспроизвести весь проект заново. Он находится на диске, прилагаемом к книге (Code\Glava3\Mail). Возможно, некоторые вопросы покажутся вам незнакомыми; после прочтения всей книги вы сможете вернуться к ним заново — тогда многое станет понятным. Подобно большинству почтовых клиентов, программа Ballet позволяет отправлять, получать, управлять почтовыми сообщениями и вложениями (рис. 3.22 и рис. 3.23). Поддерживается работа нескольких независимых пользователей и почтовых ящиков.

    (рис 3.23) Написание письма в программе Ballet(рис 3.22) Форма для получения списка в почтовом ящике

    Рассмотрим несколько деталей программы, интересных с технической точки зрения, а потом приступим к разработке программы.

    Добавление проектов

    При создании большой программы лучше всего работать над ее частями отдельно, помещая их в проекты. В папке Mail (Code\Glava3\Mail) содержатся три проекта в папках Mail 2003, SendMail и MailApplication. В папке Mail2003 содержится код для приема почтовых сообщений, в папке SendMail — код для его отправки, а в папке MailApplication находится интерфейс программы и добавлены проекты Mail из папки Mail 2003 и SendMail из одноименной папки. В терминах Visual Studio .NET любой создаваемый проект представляет собой часть разработки (решения) Solution (рис. 3.22).

    (рис 3.22) Разработка (решение) Solution в окне Solution Explorer

    При открывании ранее сохраненного проекта мы открывали именно файл NameApplication.sln, представляющий собой решение. Для добавления проектов в решение щелкаем правой кнопкой на его названии и в появившемся меню выбираем Add/New Project (новый проект) или Existing Project (существующий проект) в зависимости от того, что нам нужно (рис. 3.23):

    (рис 3.23) Добавление проектов Mail и SendMail в разработку MailApplication

    Обратите внимание на то, что само решение MailApplication содержит проект MailApplication. Проекты, объединенные в рамках одного решения, являются связанными, а не внедренными. В этом нетрудно убедиться, переименовав папку одного из проектов или внеся изменения в код: в первом случае в результирующем решении будет ошибка, во втором – изменения затронут листинги и в решении.

    Создание Мастера

    Во многих программах, когда требуется получить последовательный ряд каких-либо значений, диалоговые окна представляют в виде МастераТочный перевод c англ. слова Wizard – "волшебник", но, следуя устоявшейся традиции, я буду использовать далее слово "Мастер". (Wizard). В программе Ballet с помощью Мастера пользователь вводит необходимые параметры, причем они также проходят проверку (рис. 3.24).

    (рис 3.24) Мастер регистрации пользователя

    Форма Мастера появляется при выборе пункта главного меню "Новый пользователь" : Здесь и далее приводятся только те фрагменты кода, о которых идет речь в текущем разделе.

    private void itemNewUser_Click(object sender, System.EventArgs e)
      {
     //Создаем экземпляр wizard формы CreateUserWizard
     CreateUserWizard wizard = new CreateUserWizard();
     //Показываем форму:
     wizard.ShowDialog();
     …
      }

    Форма CreateUserWizard (рис. 3.25) представляет собой контейнер для форм CUWStep1, CUWStep2, CUWStep3.

    (рис 3.25) Родительская форма CreateUserWizard и дочерние формы CUWStep1, CUWStep2, CUWStep3 в режиме дизайна

    Обратите внимание на заголовок запущенной формы CreateUserWizard — к нему добавляются названия дочерних форм. После запуска формы CreateUserWizard в нее загружается форма CUWStep1:

    private void CreateUserWizard_Load(object sender, System.EventArgs e)
      {
     …  
     CUWStep1 step1 = new CUWStep1(identity);
     step1.MdiParent = this;
     step1.Show();
      }

    В обработчике кнопки "Далее" проверяется значение, введенное в текстовое поле, затем закрывается текущая форма и вызывается форма CUWStep2:

    private void btnNext_Click(object sender, System.EventArgs e)
      {
     if(txbEmail.Text == "")
     {
       MessageBox.Show("Введите адрес электронной почты.");
       return;
     }
     else
     {
       …
       CUWStep2 step2 = new CUWStep2(this.identity);
       step2.MdiParent = this.MdiParent;
       this.Close();
       step2.Show();
     }
      }

    В обработчике кнопки "Далее" формы CUWStep2 для проверки введенного значения снова применяется преобразование типов данных:

    private void btnNext_Click(object sender, System.EventArgs e)
    {
     if(txbPop3.Text == "")
     {
       MessageBox.Show("Введите адрес сервера POP3");
     }
     else
     {
       this.identity.Pop3 = txbPop3.Text;
       try
       {
      //Преобразовываем введенное значение в тип Int32 
      this.identity.Pop3Port = Int32.Parse(txbPop3Port.Text);
      CUWStep3 step3 = new CUWStep3(this.identity);
      step3.MdiParent = this.MdiParent;
      this.Close();
      step3.Show();
       }
       catch(Exception)
       {
      MessageBox.Show("Значение порта должно быть числом");
       }
     }
      }

    В последнем шаге Мастера необходимо закрыть не только форму CUWStep3, но также родительскую форму CreateUserWizard, которая, в свою очередь, является дочерней по отношению к главной форме mainForm. Родительская форма CreateUserWizard будет активной в этот момент, поэтому метод ActiveForm.Close() закроет ее:

    private void btnFinish_Click(object sender, System.EventArgs e)
      {
     if(txbSmtp.Text != "")
     {
       this.identity.Smtp = txbSmtp.Text;
       //Закрываем текущую форму
       this.Close();
       Thread.CurrentPrincipal = new GenericPrincipal
    (this.identity, new string[]{"user"});
       this.identity.Dispose();
       //Закрываем родительскую форму CreateUserWizard  
       Form.ActiveForm.Close();
       
     }
     else
     {
       MessageBox.Show("Введите адрес сервера SMTP");
     }
      }

    Итак, при запуске Мастера применяется форма, в которую последовательно загружаются дочерние формы. После выполнения всех действий в коде дочерней формы закрывается главная.

    Запуск формы-заставки при загрузке приложения

    При запуске программы Ballet появляется список пользователей, из которого требуется выбрать заданного для начала работы с программой (рис. 3.26).

    (рис 3.26) Форма выбора пользователя программы Ballet

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

    this.Load += new System.EventHandler(this.itemUsers_Click);

    Этот же обработчик привязан к пункту меню "Смена пользователя" в главном меню, он и вызывает форму выбора пользователя:

    private void itemUsers_Click(object sender, System.EventArgs e)
      {
     selectUser select = new selectUser();
     if(select.ShowDialog() != DialogResult.OK)
     //Запускаем главную форму.
       return;
    …
     //Вызываем метод ActivateEventItem
     this.ActivateEventItem();
      }

    В обработчике кнопки "Выбор" проверяется, выбран ли хотя бы один пользователь из списка:

    private void btnSelect_Click(object sender, System.EventArgs e)
      {
      if(lstViewUsers.SelectedItems.Count == 0)
      MessageBox.Show("Выберите пользователя для начала работы",
     "Пользователь не выбран");
      else
      {
     this.DialogResult = DialogResult.OK;
     this.Close();
      }
      }

    После выбора появляется главная форма — это указывается в обработчике itemUsers_Click. Если миновать выбор пользователя, главная форма запускается с недоступным пунктом меню "Действия". После выбора пользователя вызывается метод ActivateEventItem, в котором включается пункт меню:

    private void ActivateEventItem()
      {
     //Включаем доступность пункта меню "Действия".
     this.itemEvent.Enabled = true;
      }

    Получение сообщений – проект Mail

    Классы для обработки исключений Exceptions

    Класс CoreException.cs

    using System;
    
    namespace Mail
    {
      /// <summary>
      /// Класс для обработки  основных исключений.
      /// </summary>
      public class CoreException : ApplicationException
      {
     /// <summary>
     /// Инициализация исключения без дополнительных параметров.
     /// </summary>
     public CoreException() : base() 
     {
     }
    
     /// <summary>
            /// Инициализация исключения с дополнительным описанием.
     /// </summary>
     public CoreException(string message) : base(message) 
     {
     }
    
     /// <summary>
            /// Инициализация исключения с дополнительным описанием и внутренним исключением  
     /// </summary>
     public CoreException(string message, System.Exception inner) : base(message, inner) 
     {
     }   
      }
    }

    Класс DeadConnectionException.cs

    using System;
    
    namespace Mail
    {
      /// <summary>
        /// Класс для обработки исключений установки связи.
      /// </summary>
      public class DeadConnectException : CoreException
      {
     /// <summary>
            /// Инициализация исключения без дополнительных параметров.
     /// </summary>
     public DeadConnectException() : base() 
     {
     }
    
     /// <summary>
            /// Инициализация исключения с дополнительным описанием.
     /// </summary>
     public DeadConnectException(string message) : base(message) 
     {
     }
    
     /// <summary>
            /// Инициализация исключения с дополнительным описанием и внутренним исключением.
     /// </summary>
     public DeadConnectException(string message, System.Exception inner) : base(message, inner) 
     {
     }   
      }
    }

    Класс ParseException.cs

    using System;
    
    namespace Mail
    {
      /// <summary>
        /// Класс для обработки исключений, возникающих  в момент анализа ответа.
      /// <summary>
      public class ParseException: CoreException
      {
     public ParseException(string message) : base(message) 
     {
     }
    
     public ParseException(string message, System.Exception inner) : 
     base(message, inner) 
     {
     }   
      }
    }

    Класс ResponseException.cs

    using System;
    
    namespace Mail
    {
      /// <summary>
        /// Класс для обработки исключений POP3Unit
      /// </summary>
      public class ResponseException : CoreException
      {
     public ResponseException(string message) : base(message) 
     {
     }
    
     public ResponseException(string message, System.Exception inner) : 
     base(message, inner) 
     {
     }   
      }
    }

    Класс ShutdownException.cs

    using System;
    
    namespace Mail
    {
      /// <summary>
        /// Класс для обработки исключений POP3Unit
      /// </summary>
      public class ShutdownException: CoreException
      {
     public ShutdownException(string message) : 
     base(message) 
     {
     }
    
     public ShutdownException(string message, System.Exception inner) : 
     base(message, inner) 
     {
     }   
      }
    }

    Библиотека конвертирования Library

    Класс FromQuotedPrintableTransform.cs

    using System;
    using System.Security.Cryptography;
    using System.Text;
    
    namespace Mail
    {
      /// <summary>
      /// Конвертирование  CryptoStream.
      /// <summary>
      public class FromQuotedPrintableTransform : ICryptoTransform, IDisposable
      {
     // максимальный размер входного\выходного блока.
     const int MAX_BUF = 3;
    
     // буфер
     byte [] _buf = null;
    
     /// <summary>
            /// Значение, указывающее на возможность повторного использования текущей трансформации
     /// </summary>
     public bool CanReuseTransform
     {
       get
       {
      return true;
       }
     }
    
     /// <summary>
            /// Значение, указывающее на возможность трансформации  составных блоков.
     /// </summary>
     public bool CanTransformMultipleBlocks
     {
       get
       {
      return false;
       }
     }
    
     /// <summary>
     /// Возвращение выходного размера блока.
     /// </summary>
     public int OutputBlockSize
     {
       get
       {
      return MAX_BUF;
       }
     }
    
     /// <summary>
     /// Возвращение входного  размера  блока.
     /// </summary>
     public int InputBlockSize
     {
       get
       {
      return MAX_BUF;
       }
     }
    
     /// <summary>
     /// Удаление  всех элементов.
     /// </summary>
     public void Dispose()
     {
       _buf = null;
       GC.SuppressFinalize(this);
     }
    
    
     /// <summary>
     /// Конвертирование  указанного  участка  входящего массива байтов из quoted-printable (RFC 2045 (6.7)) 
     /// и копирование результата  в указанный участок выходного массива байтов. 
     /// </summary>
     /// <param name="inputBuffer">Входящий массив байтов.</param>
     /// <param name="inputOffset">Начальная отметка участка, который нужно конвертировать.</param>
     /// <param name="inputCount">Количество байтов после индекса начала участка.</param>
     /// <param name="outputBuffer">Выходной массив байтов, в который требуется записать результат.</param>
     /// <param name="outputOffset">Начальная отметка участка, после которого необходимо вписать результат.</param>
     /// <returns>Количество вписанных байтов.</returns>
     public int TransformBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset)
     {
       // append unparsed characters
       if (_buf != null)
       {
      byte [] tmp = new byte[inputCount + _buf.Length];
      Array.Copy(_buf, 0, tmp, 0, _buf.Length);
      Array.Copy(inputBuffer, inputOffset, tmp, _buf.Length, inputCount);
      inputBuffer = tmp;
    
      inputCount = tmp.Length;
      _buf = null;
          } 
          else 
          {
            byte [] tmp = new byte[inputCount];
            Array.Copy(inputBuffer, inputOffset, tmp, 0, inputCount);
            inputBuffer = tmp;
          }
    
          int c = 0;
          int obi = outputOffset;
    
          while (c < inputCount)
          {
            byte cb = inputBuffer[c++];
            // skip CRLFs
            if (cb == '=') 
            {
              // impossible to get next 2 bytes, save unparsed characters 
              // for next session
              if (c + 1 >= inputCount) 
              {
                int len = inputCount - c;
                _buf = new byte[len + 1]; // +1 is for '='
                Array.Copy(inputBuffer, c - 1, _buf, 0, len + 1);
                break;
              } 
                        
              // skip =\r\n
              if (!(inputBuffer[c] == '\r'  inputBuffer[c + 1] == '\n'))
              {
                // TODO Add check. Uppercase letters must be used (=DD);  
                // lowercase letters are not allowed. 
                try
                {
                  byte b = Convert.ToByte(Encoding.ASCII.GetString(inputBuffer, c, 2), 16);
                  outputBuffer[obi++] = b;
                } 
                catch (FormatException e)
                {
                  throw new ParseException("Incorrect sequence. Are you sure that it's quoted-printable?", e);
                }
              }
    
              // take next sequence
              c += 2; 
            } 
            // incorrect characters for quoted-printable, just skip it
            else if (!(cb == '\r' || cb == '\n')) 
            {          
              outputBuffer[obi++] = cb;
            }
          }
    
          return obi - outputOffset;
        }
    
        /// <summary>
        /// Конвертирование  указанного участка  входящего массива байтов из quoted-printable (RFC 2045 (6.7)).
        /// </summary>
        /// <param name="inputBuffer">Входящий массив байтов.</param>
        /// <param name="inputOffset">Начальная отметка участка, который нужно конвертировать.</param>
        /// <param name="inputCount">Количество байтов  после индекса начала участка.</param>
        /// <returns>Полученный массив байтов.</returns>
        public byte[] TransformFinalBlock(byte[] inputBuffer, int inputOffset, int inputCount)
        {
          byte [] b = new byte[inputCount];
          int s = TransformBlock(inputBuffer, inputOffset, inputCount, b, 0);
    
          byte [] c = new byte[s];
          Array.Copy(b, 0, c, 0, s);
          return c;
        }
      }
    }

    Класс Utils.cs

    using System;
    using System.Text.RegularExpressions;
    using System.Collections;
    using System.Text;
    using System.Web;
    
    namespace Mail
    {
      /// <summary>
      /// Класс, содержащий общие функции.
      /// </summary>
      public class Utils
      {
        // Архив кодировок.
        static Hashtable knownEncodings = new Hashtable();
    
        static Utils()
        {
    
        }
        /// <summary>
        /// Извлечение  простого текста из HTML-текста.
        /// </summary>
        /// <param name="html">HTML текст.</param>
        /// <returns>Простой текст.</returns>
        public static string ExtractTextFromHtml(string html)
        {
          // С помощью регулярных выражений удаляем или заменяем
          // HTML-теги.
          // удаление  <!DOCTYPE ... >
          Regex r = new Regex(@"<![^>]+>"); // Создание регулярного выражения.
          html = r.Replace(html, ""); // Замена подходящей части текста на пустую строку.
    
          // удаление <head>...</head>
          r = new Regex(@"<head>.*?</head>", RegexOptions.IgnoreCase); // Создание регулярного выражения.
          // r = new Regex(@"<style[^>]+[>].*?</style>", RegexOptions.IgnoreCase);
          html = r.Replace(html, ""); // Замена подходящей части текста на пустую строку.
          // представляем, что </div>, <br />, </p> — это новая строка
          r = new Regex(@"(</div>|<[/]?br[^>]+>|</p>)", RegexOptions.IgnoreCase); // Создание регулярного выражения.
          html = r.Replace(html, "\r\n"); // Замена подходящей части текста на символы перехода на новую строку.
    
          // удаление всех тегов <...>
          r = new Regex(@"<[^>]+>", RegexOptions.Multiline); // Создание регулярного выражения, удаляющего все оставшиеся теги.
          html = r.Replace(html, ""); 
                html = HttpUtility.HtmlDecode(html);
          return html;
        }
    
        /// <summary>
        /// Возвращение  кодировки текста.
        /// </summary>
        /// <param name="charset">Текст, содержащий название кодировки.</param>
        /// <returns></returns>
        public static Encoding GetEncoding(string charset)
        {
          // Проверяем, есть ли данная кодировка в памяти класса,
          // и если есть, возвращаем ее.
          if (knownEncodings.ContainsKey(charset)) 
          {
            return (Encoding)knownEncodings[charset];
          }
          // Если кодировка не обнаружена,  начинаем анализировать строку.
          Encoding e = Encoding.Default;
          try
          {
            e = Encoding.GetEncoding(charset);
          }
          catch {}
    
          // Добавляем кодировку в память класса.
          knownEncodings.Add(charset, e);
          // Возвращаем кодировку.
          return e;
        }
    
    
        /// <summary>
        /// Исключаем "byte-stuffed", следуя RFC1939 
        /// \r\n.[not \r\n] => \r\n[not \r\n]
        /// </summary>
        /// <param name="s"></param>
        /// <returns></returns>
        public static string RemoveByteStuffedSequence(string s)
        {
          Regex r = new Regex(@"(?<=\r\n)\.(?!\r\n)");
          return r.Replace(s, "");
        }
    
        /// <summary>
            /// Декодируем строку
        /// </summary>
        /// <param name="s">Строка</param>
        /// <returns></returns>
        public static string DecodeQuotedPrintable(string s, Encoding e)
        {
          _curEncoding = e;
          Regex re = new Regex(@"=([a-fA-F0-9]{2})");
          return re.Replace(s, new MatchEvaluator(ReDigit));
        }
    
    
        static Encoding _curEncoding;
        /// <summary>
            /// Конвертирует "ХХ" в байтовый аналог
        /// </summary>
        /// <param name="match">"XX" формат</param>
        /// <returns></returns>
        static string ReDigit(Match match)
        {
          byte [] tmp = {Convert.ToByte(match.Groups[1].Value, 16)};
          return "" + _curEncoding.GetString(tmp);
        }
    
        /// <summary>
        /// RFC 2047
        /// </summary>
        /// <param name="s"<</param>
        /// <returns<</returns>
        public static string WordDecoder(string input)
        {
          string charset = "";
          string src;
          string tmp;
          src = input;
          Match m = Regex.Match(input, @"(?<ew>(?<n>\=\?(?<charset>[^?]+)\?(?<encoding>[QqBb])\?(?<content>[^?]+)\?\=)(\r\n)*\s*)(?=(?<isnext>\=\?[^?]+\?[QqBb]\?[^?]+\?\=)*)", RegexOptions.Multiline);
          if (m.Success)
          {
            while (m.Success)
            {
              charset = m.Groups["charset"].Value;
              string encoding = m.Groups["encoding"].Value.ToLower();
              switch(encoding)
              {
                case "q":
                  tmp = m.Groups["content"].Value.Replace("_", " ");
                  tmp = DecodeQuotedPrintable(tmp, GetEncoding(m.Groups["charset"].Value));
                  break;
    
                case "b":
                  tmp = GetEncoding(charset).GetString(Convert.FromBase64String(m.Groups["content"].Value));
                  break;
    
                default:
                  throw new ParseException("Неизвестный метод кодировки");
              }
    
              src = src.Replace(((m.Groups["isnext"].Value.Length == 0) ? m.Groups["n"].Value : m.Groups["ew"].Value), tmp);
              m = m.NextMatch();
            }
    
            return src; 
          }
    
          return GetEncoding(charset).GetString(Encoding.Default.GetBytes(src));
        }
      }
    }

    Формирование сообщений

    Класс MessageFile.cs

    namespace Mail.Providers
    {
      using System;
      using System.IO;
      using System.Diagnostics;
      using System.Text;
    
      /// <summary>
      /// Провайдер для .eml-файлов.
      /// </summary>
      public class MessageFile : Provider
      {
        const string FiveOctalTerm = "\r\n.\r\n";
    
        FileStream fs = null;
    
        /// <summary>
        /// Конструктор.
        /// </summary>
        /// <param name="filename">Адрес к файлу.</param>
        public MessageFile(string filename)
        {
                fs = new FileStream(filename, FileMode.Open, FileAccess.Read);
          TempDirectory = Path.GetTempPath();
        }
    
        /// <summary>
            /// Не реализовано
        /// </summary>
        /// <param name="i"></param>
        public override void DeleteMessage(uint index)
        {
                Debug.WriteLine("Не реализовано");
        }
    
        string TruncateTail(string message)
        {
          if (!message.EndsWith(FiveOctalTerm))
          {
                    Debug.WriteLine("Последние 5 символов: {" + message.Substring(message.Length - 5) + "}");
                    throw new ResponseException("Неправильные символы конца сообщения.");
          }
    
          return message.Remove(message.Length — FiveOctalTerm.Length, FiveOctalTerm.Length);
        }
    
        /// <summary>
        /// Не реализовано.
        /// </summary>
        /// <param name="i"></param>
        public override Message GetMessage(uint index)
        {
          byte [] buf = new byte[fs.Length];
          fs.Read(buf, 0, buf.Length);
          fs.Position = 0;
    
          string message = Utils.RemoveByteStuffedSequence(Encoding.ASCII.GetString(buf));
          return new Message(this, message, index);
        }
    
        /// <summary>
        /// Этот метод необязателен.
        /// </summary>
        /// <param name="name"></param>
        /// <param name="pass"></param>
        public override void LogIn(string name, string pass)
        {
                Debug.WriteLine("Не реализовано");
        }
    
        /// <summary>
        /// Закрытие потока.
        /// </summary>
        public override void Dispose()
        {
          try
          {
            Quit();
          } 
          catch
          {
          }
    
                GC.SuppressFinalize(this);      
        }
    
        /// <summary>
        /// Закрытие FilеStream.
        /// </summary>
        public override void Quit()
        {
                fs.Close();
        }
      }
    }

    Класс MaildropStatus.cs

    using System.Collections;
    
    namespace Mail.Providers
    {
      /// <summary>
      /// Содержание информации о почтовом ящике  (размер и количество сообщений).
      /// </summary>
      class MaildropStatus
      {
        internal uint messages;
        internal uint size;
    //    internal Hashtable messagelist;
    
        /// <summary>
            /// Конструктор с параметрами: количество сообщений и размер.
        /// </summary>
            /// <param name="messages">Количество сообщений.</param>
        /// <param name="size">Размер сообщений.</param>
        public MaildropStatus(uint messages, uint size)
        {
          this.messages = messages;
          this.size = size;
        }
      }
    }

    Класс Pop3.csM

    //#define _DEBUG
    
    using System;
    using System.IO;
    using System.Net;
    using System.Net.Sockets;
    using System.Diagnostics;
    using System.Collections;
    using System.Text;
    using System.Text.RegularExpressions;
    
    namespace Mail.Providers
    {
      /// <summary>
      /// Реализация протокола POP3
      /// </summary>  
      /// <example>Пример получения сообщения.
      /// <code>
      /// using (Pop3 pop3 = new Pop3("host"))
      ///  {
      ///    pop3.LogIn("Username", "Password");
      ///    Console.WriteLine("Количество сообщений:" + pop3.NumberOfMessages);
      ///    
      ///    using(Message msg = pop3.GetMessage(1)) // получение первого сообщения
      ///    {
      ///      Console.WriteLine("Тема: " + msg.Subject); 
      ///    }
      ///  }
      /// </code>
      /// </example>  
      public class Pop3 : Provider
      {
        #region Constants
        const int MaxReceiveSize = 1024;
        const int POP3DefaultPort = 110;
    
        const int SendTimeout = 60000; // в милисекундах.
            public int ReceiveTimeout = 2000000; // в милисекундах.
            public int PollTimeout = 100000; // в микросекундах.
    
        const string CRLF = "\r\n";
        
        const string FiveOctalTerm = "\r\n.\r\n";
        const string STAT_OK = "+OK";
        const string STAT_ERR = "-ERR";
    
        const char SPACE = ' ';
        const char CR = '\r';
        #endregion
    
        Socket _socket = null;
    
            MaildropStatus _status = null;
        uint [] _messagelist = null;
    
        bool _authenticated = false;
    
        #region DEBUG functions
        FileStream GetDebugStream()
        {
          return new FileStream(@"C:\trace_response.log", FileMode.Append);
        }
        [Conditional("_DEBUG")]
        void Trace(byte [] str)
        {
          FileStream fs = GetDebugStream();
          fs.Write(str, 0, str.Length);
          fs.Close();
        }
    
        [Conditional("_DEBUG")]
        void Trace(string str)
        {
          FileStream fs = GetDebugStream();
          fs.Write(Encoding.ASCII.GetBytes(str), 0, str.Length);
          fs.Close();
        }
        #endregion
    
        #region Constructors 
        /// <summary>
            /// Инициализация класса установленным по умолчанию портом (110) и установка  адреса временной папки 
            /// на текущую системную временную папку.    
        /// </summary>
        /// <param name="server">IP адрес сервера.</param>
        public Pop3(string server)
        {
          _server = server;
          _port = POP3DefaultPort;
          TempDirectory = Path.GetTempPath();
        }
    
        /// <summary>
            /// Инициализация класса а установленным по умолчанию портом (110).
        /// </summary>
            /// <param name="server">IP адрес сервера.</param>
        /// <param name="temp">Адрес временной папки.</param>
        public Pop3(string server, string temp)
        {
          _server = server;
          _port = POP3DefaultPort;
          TempDirectory = temp;
        }
    
        /// <summary>
        /// Инициализация класса .
        /// </summary>
            /// <param name="server">IP адрес сервера.</param>
        /// <param name="port">Номер порта.</param>
        public Pop3(string server, int port)
        {
          _server = server;
          _port = port;
          TempDirectory = Path.GetTempPath();
        }
    
        /// <summary>
            /// Инициализация класса .
        /// </summary>
            /// <param name="server">IP-адрес сервера.</param>
            /// <param name="port">Номер порта.</param>
            /// <param name="temp">Адрес временной папки.</param>
        public Pop3(string server, int port, string temp)
        {
          _server = server;
          _port = port;
          TempDirectory = temp;
        }
        #endregion
    
        #region Public properties
        /// <summary>
        /// Возвращается значение  true, если в почтовом ящике есть сообщения.
        /// </summary>
        public bool IsMessages
        {
          get 
          {
            return (NumberOfMessages > 0);
          }
        }
    
        /// <summary>
        /// Количество сообщений в ящике.
        /// </summary>
        public uint NumberOfMessages
        {
          get 
          {
            // not initialized
            if (_status == null)
            {
              GetStatus();
            }
    
            return _status.messages;
          }  
        }
        #endregion
    
        #region Method-Property substitution
            /// <summary>
            /// Получение количества сообщений.
            /// </summary>
            /// <returns></returns>
        public uint GetNumberOfMessages()
        {
                return NumberOfMessages;
        }
            
        public bool GetIsMessages()
        {
          return IsMessages;
        }
        #endregion
    
        /// <summary>
            /// Анализ количества  строк, полученных  от сервера после отправки команды STAT.    
        /// </summary>
            /// <example>Команда STAT. В ответ на вызов команды сервер выдает положительный ответ "+OK", 
            /// за которым следует количество сообщений в почтовом ящике и их общий размер в символах. 
            /// Сообщения, которые помечены для удаления, не учитываются в ответе сервера. 
            /// </example>
        void GetStatus()
        {
          CheckConnection();
    
          Send("STAT");
          string tmp = Receive();
    
          string [] tokens = tmp.Split(new Char[] {SPACE, CR}, 4);
    
          try
          {
            _status = new MaildropStatus(
              Convert.ToUInt32(tokens[1], 10), 
              Convert.ToUInt32(tokens[2], 10)
            );
          } 
          catch (Exception e)
          {
                    throw new CoreException("Невозможно проанализировать ответ", e);
          }
        }
            /// <summary>
            /// Установка соединения с сервером.
            /// </summary>
            /// <param name="server">Название сервера.</param>
            /// <param name="port">Номер порта.</param>
        void EstablishConnection(string server, int port)
        {
          // Получение IP-адреса сервера.
          IPAddress ipadr = Dns.Resolve(server).AddressList[0];
          IPEndPoint ephost = new IPEndPoint(ipadr, port);
     
          // Создание Socket для передачи данных по протоколу TCP.
          _socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
    
          
          LingerOption linger = new LingerOption(true, 10);
          _socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Linger, linger);
          // Установка времени ожидания.
          _socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.SendTimeout, SendTimeout);
          _socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout, ReceiveTimeout);
    
          // Соединение с сервером.
          _socket.Connect(ephost);
          if (!_socket.Connected)
          {
            throw new CoreException("Сервер не найден: " + server);
          }
        }
    
        /// <summary>
        /// Проверка соединения и авторизации пользователя.
        /// </summary>
        void CheckConnection()
        {
          if (_socket == null || !_socket.Connected) 
          {
            throw new CoreException("Соединение не установлено.");
          }
    
          if (!_authenticated)
          {
                    throw new CoreException("Пользователь не аутентифицирован (Метод LogIn). ");
          }
        }
            /// <summary>
            /// Отправка команды на сервер.
            /// </summary>
            /// <param name="command">Текст команды.</param>
        void Send(string command)
        {
                // Все команды заканчиваются парой CRLF.
          command += CRLF;
                // Сервер работает с кодировкой ASCII.
          Encoding tmp = Encoding.ASCII;
          Byte [] buf = tmp.GetBytes(command);
    
          int total = buf.Length;
          while (total > 0)
          {
            total -= _socket.Send(buf, command.Length, SocketFlags.None);
          }
        }
            /// <summary>
            /// Анализ POP3-строки.
            /// </summary>
            /// <param name="str">Строка.</param>
        void AnalyseResponse(string str)
        {
          Trace(str);
    //      Debug.WriteLine(str);
    
          if (str.StartsWith(STAT_ERR))
          {
            string msg;        
            int i = str.IndexOf(CRLF);
            if (i < 0) 
            {
              msg = "Ответ сервера: " + STAT_ERR;
            } 
            else
            {
              // Если ответ слишком большой, отсекаем  его.
              msg = str.Substring(STAT_ERR.Length + 1, Math.Min(i - STAT_ERR.Length - 1, 79));
            }
    
            throw new ResponseException(msg);
          }
        }
    
        /// <summary>
        /// Получение сообщения в POP3-формате.
        /// </summary>
        /// <param name="index">Номер сообщения.</param>
        /// <returns></returns>
        public StringReader DumpMessage(int index)
        {
          CheckConnection();
    
          Send("RETR " + index);
          return new StringReader(Receive());
        }
            /// <summary>
            /// Удаление символов конца сообщения.
            /// </summary>
            /// <param name="message">Сообщение.</param>
            /// <returns></returns>
        string TruncateTail(string message)
        {
          if (!message.EndsWith(FiveOctalTerm))
          {
            Debug.WriteLine("Последние 5 символов: {" + message.Substring(message.Length — 5) + "}");
            throw new ResponseException("Неправильные символы конца сообщения.");
          }
    
                return message.Remove(message.Length — FiveOctalTerm.Length, FiveOctalTerm.Length);
        }
    
        /// <summary>
        /// Получение существующих номеров сообщений.
        /// </summary>
        /// <returns>Массив с существующими индексами сообщений.</returns>
            /// <example>Команда LIST. Сервер выдает информацию о всех сообщениях, находящихся в почтовом ящике. 
            /// Сообщения, помеченные для удаления, не перечисляются. 
            /// </example>
        public uint[] ListMessages()
        {
          CheckConnection();
    
          if (_messagelist == null)
          {
            Send("LIST");
            string tmp = Receive();
            tmp = TruncateTail(tmp);
            int start = tmp.IndexOf(CRLF);
            if (start > 0)
            {
              start += CRLF.Length;
              ArrayList l = new ArrayList();
              Regex r = new Regex(@"\r\n");
              string [] list = r.Split(tmp.Substring(start));
              if (list.Length > 0)
              {
                foreach (string s in list)
                {
                  string [] f = s.Split(new char [] {' '}, 2);
                  l.Add(Convert.ToUInt32(f[0], 10));
                }
              }
    
              if (l.Count > 0)
              {
                _messagelist = (uint [])l.ToArray(typeof(uint));
              }
              else
                _messagelist = new uint[0];
            } else 
              _messagelist = new uint[0];
          }
    
          return _messagelist;
        }
    
        /// <summary>
        /// Отправляет команду NOOP на сервер. 
        /// </summary>
        /// <remarks>
        /// <para>Используется для поддержания сеанса с сервером.</para>
        /// </remarks>
            /// <example>Команда NOOP. POP3-сервер ничего не делает и всегда отвечает положительно. 
            /// </example>
        public void SendNoop()
        {
          CheckConnection();
    
          Send("NOOP");
          string tmp = Receive();
        }
    
        /// <summary>
        /// Возвращает уникальный идентификатор сообщения.
        /// </summary>
        /// <remarks>
            /// <para>
            /// Если сообщение помечено на удаление, оно не учитывается.
        /// </para>
        /// </remarks>
        /// <param name="index">Номер сообщения.</param>
        /// <returns>Уникальный идентификатор пользователя.</returns>
        public string GetMessageUniqueID(uint index)
        {
          CheckConnection();
    
          Send("UIDL " + index);
          string tmp = Receive();
    
          string [] f = tmp.Split(new char [] {' ', '\r', '\n'}, 4);
                return f[2];            
        }
    
        /// <summary>
        /// Получение заголовка сообщения.
        /// </summary>    
        /// <param name="index">Сообщение.</param>
        /// <param name="liens">Количество первых строк.</param>
        /// <returns>Сообщение с анализированными заголовками.</returns>
            /// <example>Команда TOP. Если ответ сервера положительный, 
            ///  он передает заголовки сообщения и указанное количество строк из тела сообщения.
            /// </example>
        public Message GetMessageHeader(uint index, int top)
        {
          CheckConnection();
    
          Send("TOP " + index + " " + top);
          string message = Receive();
    
          message = Utils.RemoveByteStuffedSequence(message);
          return new Message(this, TruncateTail(message), index);
        }
    
        /// <summary>Удаление сообщения.
        /// </summary>
        /// <param name="index">Номер сообщения.</param>
            /// <example>Команда DELETE. POP3-сервер помечает указанное сообщение как удаленное, 
            /// но не удаляет его, пока сессия не перейдет в режим UPDATE. 
            /// </example>
        public override void DeleteMessage(uint index)
        {
          CheckConnection();
    
          Send("DELE " + index);
          string tmp = Receive();
        }
    
        /// <summary>
        /// Получение сообщения.
        /// </summary>
        /// <param name="index">Номер сообщения.</param>
        /// <returns>Сообщение.</returns>
            /// <example>Команда RETR. После положительного ответа сервер передает содержание сообщения.        
            /// </example>
        public override Message GetMessage(uint index)
        {
          CheckConnection();
    
                Send("RETR " + index);
                string message = ReceiveMessage();
    
          message = Utils.RemoveByteStuffedSequence(message);
                return new Message(this, TruncateTail(message), index);
        }
    
        public void OnRecievedData( IAsyncResult ar )
        {
        }
    
            /// <summary>
            /// Получение ответа сервера без проверки подлинности.
            /// </summary>
            /// <returns>Ответ сервера.</returns>
        StringBuilder UnsafeReceive()
        {
          StringBuilder tmp = new StringBuilder();
          Encoding cenc = Encoding.ASCII;
          IAsyncResult asynResult;
          byte[] buf = new byte[1024];
          int recv = 0;      
          do
          {
            asynResult = _socket.BeginReceive(buf, 0, buf.Length, SocketFlags.None, null, null);
            if (asynResult.AsyncWaitHandle.WaitOne())
            {
              recv = _socket.EndReceive(asynResult);
              string t = cenc.GetString(buf, 0, recv);
              tmp.Append(t);
              if (t.LastIndexOf(FiveOctalTerm) > 0) break;
            }
          }
          while(_socket.Poll(PollTimeout, SelectMode.SelectRead));
    
                return tmp;
        }
        /// <summary>
        /// Получение ответа сервера без проверки подлинности.
        /// </summary>
        /// <returns>Ответ сервера.</returns>
        StringBuilder UnsafeReceiveMessage()
        {
          StringBuilder tmp = new StringBuilder();
          Encoding cenc = Encoding.ASCII;
          IAsyncResult asynResult;
          byte[] buf = new byte[1024];
          int recv = 0;      
          do
          {
            asynResult = _socket.BeginReceive(buf, 0, buf.Length, SocketFlags.None, null, null);
            if (asynResult.AsyncWaitHandle.WaitOne())
            {
              recv = _socket.EndReceive(asynResult);
              string t = cenc.GetString(buf, 0, recv);
              tmp.Append(t);
              //if (t.LastIndexOf(FiveOctalTerm) > 0) 
              //  break;
            }
          }
          while(!tmp.ToString().EndsWith(FiveOctalTerm));
    
          return tmp;
        }
        /// <summary>
        /// Возвращение  ответа сервера.
        /// </summary>
        /// <returns>Ответ сервера.</returns>
        string Receive()
        {
          StringBuilder tmp = UnsafeReceive();
                string str = tmp.ToString();
          AnalyseResponse(str);
    
          return str;
        }
        /// <summary>
        /// Возвращение сообщения в виде строки.
        /// </summary>
        /// <returns></returns>
        string ReceiveMessage()
        {
          StringBuilder tmp = UnsafeReceiveMessage();
          string str = tmp.ToString();
          AnalyseResponse(str);
    
          return str;
        }
            /// <summary>
            /// Аутентификация пользователя.
            /// </summary>
            /// <param name="username">Имя пользователя.</param>
            /// <param name="password">Пароль.</param>
            /// <example>После установки соединения сервер находится в режиме авторизации пользователя.
            /// Пользователь должен идентифицировать себя на сервере, используя команды USER и PASS. 
            /// Сначала надо отправить команду USER, после которой в качестве аргумента следует имя пользователя. 
            /// Если сервер отвечает положительно, то теперь необходимо отправить команду PASS, за которой следует пароль.
            /// <code>
            /// Client: USER username
            /// Server: +OK username
            /// Client: PASS mypass
            /// Server: +OK username
            /// </code>
            /// </example>
        void AuthenticateYourSelf(string username, string password)
        {
          Send("USER " + username);
          Receive();
                Send("PASS " + password);
          Receive();
    
          _authenticated = true;
        }
    
        /// <summary>
            /// Соединение с сервером и аутентификация пользователя.
        /// </summary>
        /// <param name="username">Имя пользователя.</param>
        /// <param name="password">Пароль.</param>
        public override void LogIn(string username, string password)
        {
          try
          {
            if (_socket != null) 
            {
              Quit();
              ResetVariables();
            }
                    // Установка соеденения.
            EstablishConnection(_server, _port);
            Receive(); // Получение приветствия от сервера.
            AuthenticateYourSelf(username, password);
          }
          catch (ShutdownException e)
          {
                    throw new CoreException("Невозможно завершить предыдущий сеанс.", e);
          }
          catch (Exception e)
          {
            throw new CoreException("Вход невозможен", e);
          }
        }
    
        /// <summary>
        /// Закрытие транзакции на сервере.
        /// </summary>
        public override void Quit()
        {
          try
          {
            CheckConnection();
                    // Сервер завершает POP3-сессию и переходит в режим UPDATE.
            Send("QUIT"); // Ответ нас не интересует
          }
          catch (Exception e)
          {
            throw new ShutdownException("Невозможно покинуть транзакцию", e);
          }
    
          CloseSocket();
        }
    
        /// <summary>
        /// Свойство закрытия соединения.
        /// </summary>
        void CloseSocket()
        {
          try
          {
            _socket.Shutdown(SocketShutdown.Both);
            _socket.Close();
            // Свойство 'Connected'  установлено в false, когда соединение закрыто.
            if (_socket.Connected) 
            {
              throw new CoreException("При закрытии socket возникло исключение: " + 
                Convert.ToString(System.Runtime.InteropServices.Marshal.GetLastWin32Error()));
            }
    
            _socket = null;
          }
          catch (SocketException e)
          {
                    throw new CoreException("Невозможно закрыть socket", e);
          }
        }
            /// <summary>
            /// Сброс переменных.
            /// </summary>
        void ResetVariables()
        {
          _authenticated = false;
          _status = null;
          _messagelist = null;
        }
    
        /// <summary>
        /// Закрытие сеанса.
        /// </summary>
        public override void Dispose()
        {
          try
          {
            Quit();
            ResetVariables();
          } 
          catch // Обработчик всех возникших исключений.
          {
            Debug.WriteLine("Невозможно закрыть socket");
          }
    
          GC.SuppressFinalize(this);
        }
      }
    }

    Класс Provider.cs

    namespace Mail.Providers
    {
      using System;
    
      /// <summary>
        /// Общий абстрактный класс для всех провайдеров.  
      /// </summary>
      public abstract class Provider : IDisposable
      {
            /// <summary>
            /// Название сервера.
            /// </summary>
        protected string _server;
            /// <summary>
            /// Номер порта.
            /// </summary>
        protected int _port;
        /// <summary>
        /// Временная папка для записи временных файлов.
        /// </summary>
        string _tempdir;
    
        /// <summary>
        /// Метод авторизации пользователя.
        /// </summary>
        /// <param name="login">Имя пользователя.</param>
        /// <param name="password">Пароль.</param>
        public abstract void LogIn(string login, string password);
    
        /// <summary>
        /// Закрытие сеанса.
        /// </summary>
        public abstract void Quit();
    
        /// <summary>
        /// Удаление сообщения.
        /// </summary>
        /// <param name="index">Номер сообщения.</param>
        public abstract void DeleteMessage(uint index);
    
        /// <summary>
        /// Получение сообщения.
        /// </summary>
            /// <param name="index">Номер сообщения.</param>
        public abstract Message GetMessage(uint index);
    
    
        /// <summary>
        /// Путь к временной папке.
        /// </summary>
        public string TempDirectory
        {
          get
          {
            return _tempdir;
          }
          set
          {
            _tempdir = value;
          }
        }
    
        /// <summary>
        /// Уничтожение объекта.
        /// </summary>
        abstract public void Dispose();
      }
    }

    Обработка вложений. Класс AttachDescriptor.cs

    using System;
    using System.IO;
    using System.Security.Cryptography;
    using System.Text;
    
    namespace Mail
    {
      /// <summary>
        /// Содержит методы и информацию о вложениях в письмо.
      /// </summary>
      public class AttachDescriptor
      {
        string _oldname;
        string _tmpfile;
    
        internal AttachDescriptor(string name, string dir)
        {
          _oldname = name;
          _tmpfile = dir + Guid.NewGuid();
        }
        /// <summary>
        /// Декодирование  файла.
        /// </summary>
        /// <param name="message">Текст сообщения с вложенным файлом.</param>
        /// <param name="transform">Формат трансформации.</param>
        internal void DecodeFile(string message, ICryptoTransform transform)
        {
          try 
          {
            // Создаем временный файл.
            FileStream tf = new FileStream(_tmpfile, FileMode.Create, FileAccess.Write);
            // Создаем поток трансформации для временного файла.
            CryptoStream cs = new CryptoStream(tf, transform, CryptoStreamMode.Write);
            
            // Конвертируем  строки в массив байтов
            Encoding enc = Encoding.ASCII;
            byte [] b = enc.GetBytes(message);
            // Записываем байты в поток трансформации.
            cs.Write(b, 0, b.Length);
            // Закрываем потоки.
            cs.Close();
            tf.Close();
          } 
          // Обрабатываем  возникшие исключения.
          catch(System.Exception e)
          {
            Console.WriteLine(e.ToString());
            throw new ParseException("Невозможно декодировать содержимое файла", e);
          }
        }
        /// <summary>
        /// Закрываем  и удаляем  временный файл.
        /// </summary>
        internal void Close()
        {
          File.Delete(_tmpfile);            
        }
    
        /// <summary>
            /// Возвращаем  файловый поток из  файла временного вложения.
        /// </summary>
        /// <returns></returns>
        public FileStream GetFile()
        {
          FileStream tf = new FileStream(_tmpfile, FileMode.Open, FileAccess.Read);
          return tf;
        }
    
        #region Public properties
            /// <summary>
            /// Название.
            /// </summary>
        public string Name
        {
          get
          {
                    return _oldname;
          }
        }
            /// <summary>
            /// Временный файл.
            /// </summary>
        public string TempFile
        {
          get
          {
            return _tmpfile;
          }
        }
            /// <summary>
            /// Размер.
            /// </summary>
        public long Size
        {
          get
          {
            FileInfo fi = new FileInfo(_tmpfile);
            return fi.Length;
          }
        }
        #endregion
      }
    }

    Основной класс сообщения. Common.cs

    namespace Mail
    {
      using System;
      using System.Collections;
      using System.IO;
      using System.Text;
      using System.Text.RegularExpressions;
      using System.Security.Cryptography;
    
      using Mail.Providers;
    
      /// <summary>
      /// Основной класс для <see cref="Mime"/> и <see cref="Message"/>.
      /// Содержит общую информацию и различные методы.
      /// </summary>
      public class Common
      {
        internal const string DCRLF = "\r\n\r\n";
        internal const string CRLF = "\r\n";
        internal const char Colon = ':';
        internal const string MIMEE = "--";
    
        internal string _message;
        internal long _size;
    
        internal Provider _pop3;
    
        public Provider Parent
        {
          get
          {
            return _pop3;
          }      
        }
    
        /// <summary>
        /// Список sub-mimes.
        /// </summary>
        public Mime [] ChildMimes = new Mime[0];
    
        /// <summary>
        /// Заголовки.
        /// </summary>
        internal Hashtable Headers = new Hashtable();
    
        /// <summary>
            /// Содержит все заголовки из <see cref="Message"/> или <see cref="Mime"/>
        /// </summary>
        /// <remarks>
            /// Все заголовки должны быть в нижнем регистре.
        /// </remarks>
        public Hashtable AllHeaders
        {
          get
          {
                    return Headers;
          }
        }
    
        /// <summary>
        /// Размер сообщения.
        /// </summary>
        public long GetSize()
        {
          return _size;      
        }
        /// <summary>
        /// Подготовка  строки в зависимости от кодировки сообщения.
        /// </summary>
        /// <param name="mes">Текст сообщения.</param>
        /// <returns></returns>
        internal string PreparedString(string mes)
        {
          string t;
          switch (TransferEncoding)
          {
            case "base64":
              t = DecodeMessage(mes, new FromBase64Transform());
              break;
    
            case "quoted-printable":
              t = DecodeMessage(mes, new FromQuotedPrintableTransform());
              break;
    
            default:
              t = mes;
              break;
          }
    
          return t;
        }
        /// <summary>
        /// Подготовка  тела сообщения.
        /// </summary>
        /// <returns></returns>
        internal string PreparedBody()
        {
          
          return PreparedString(_message);
        }
        /// <summary>
        /// Декодируем сообщение.
        /// </summary>
        /// <param name="message">Текст сообщения.</param>
        /// <param name="transform">Тип трансформации.</param>
        /// <returns></returns>
        string DecodeMessage(string message, ICryptoTransform transform)
        {
          MemoryStream tf = new MemoryStream();
          CryptoStream cs = new CryptoStream(tf, transform, CryptoStreamMode.Write);
            
          // конвертируем  строки в массив байтов
          Encoding enc = Encoding.ASCII;
          byte [] b = enc.GetBytes(message);
          cs.Write(b, 0, b.Length);
    
          cs.Close();
          string t = Utils.GetEncoding(Charset).GetString(tf.ToArray());
          tf.Close();
          return t;
        }
        /// <summary>
        /// Конструктор.
        /// </summary>
        /// <param name="parent">Родительский провайдер.</param>
        /// <param name="message">Текст, содержащий сообщение.</param>
        internal Common(Provider parent, string message)
        {
          if (parent == null)
          {
            throw new ArgumentNullException("parent");
          }
          if (message == String.Empty)
          {
            throw new ArgumentException("empty string", "message");
          }
    
          int end = FillHeaders(message);
          _size = message.Length;
    
          // исключаем заголовок из тела сообщения
          _message = message.Substring(end);
          _pop3 = parent;
        }
    
        /// <summary>
            /// Выбираем все заголовки и заполняем массив.
        /// </summary>
        /// <returns></returns>
        internal int FillHeaders(string message)
        {
          int start = 0; //message.IndexOf(CRLF) + CRLF.Length; //пропускаем 2 байта
          int headerend = message.IndexOf(DCRLF); 
          string headers = message.Substring(start, headerend - start);
          GetHeaders(headers);
    
          // пропускаем секцию заголовков
          headerend += DCRLF.Length;
    
          return headerend;
        }
    
        /// <summary>
        /// Заполнение  <see cref="Mime"/> массива.
        /// </summary>
        /// <returns></returns>
        protected bool MultipartMixed()
        {
          string b = GetBoundary();
          if (b == String.Empty) return false;
    
          int s = _message.IndexOf(b);
          if (s < 0)
          {
            throw new ParseException("Can't find beginning MIME boundary: " + b);
          }
    
          ArrayList tmimes = new ArrayList();
          
          while(true)
          {
            s += b.Length + CRLF.Length;
    
            int e = _message.IndexOf(b, s);
            if (e < 0)
            {          
              if (_message.IndexOf(MIMEE, s - CRLF.Length, MIMEE.Length) < 0)
              {
                throw new ParseException("Неправильный MIME");
              }
    
              break;
            }
                          
    
            tmimes.Add(new Mime(_pop3, _message.Substring(s, e - s - CRLF.Length)));
            s = e;
          }
    
          ChildMimes = (Mime [])tmimes.ToArray(typeof(Mime));
                
          return true;
        }
    
    
        /// <summary>
        /// Попытка извлечения значения 'boundary' из <see cref="ContentType"/>.
        /// </summary>
        /// <returns></returns>
        protected string GetBoundary()
        {      
          Regex r = new Regex("boundary=[\\\"]?([^\\r\\\"]+)");
          if (ContentType == null)
          {
                    return String.Empty;
          }
    
          Match m = r.Match(ContentType);
          if (m.Success)
          {
            return "--" + m.Groups[1].ToString();
          }
          else
          {
            return String.Empty;
          }
        }
    
    
    
        /// <summary>
        /// Все заголовки в нижнем регистре.
        /// </summary>
        /// <param name="top">Заголовок</param>
        void GetHeaders(string top)
        {      
          Regex line = new Regex(@"\r\n(?![\t\x20])");
          string [] col = line.Split(top);
          foreach (string s in col)
          {
            string [] fields = s.Split(new Char[] {':'}, 2);
            //        Console.WriteLine(fields[0] + "}={" + fields[1] + "}");
            if (fields.Length < 2) continue;
            fields[0] = fields[0].ToLower(); // перевод в нижний регистр
            fields[1] = fields[1].TrimStart(' '); // удаление ненужных пробелов
    
            
            if (Headers.ContainsKey(fields[0]))
            {
              object oldv = Headers[fields[0]];
              ArrayList al = oldv as ArrayList;
              if (al == null)
              {
                al = new ArrayList();
                al.Add(oldv); 
                Headers[fields[0]] = al;
              } 
    
              al.Add(fields[1]);
            } 
            else 
            {
              Headers.Add(fields[0].ToLower(), fields[1]);
            }
          }
        }
    
        #region Common headers
        public string Charset
        {
          get
          {
            Regex r = new Regex(@"charset=[""'\s]([^""'\s]+)");
            Match m = r.Match(ContentType);
            if (m.Success)
              return m.Groups[1].Value;
            else
              return "";
          }
        }
    
        protected string TransferEncoding
        {
          get
          {
            return ((string)Headers["content-transfer-encoding"]).ToLower();
          }
        }
    
        /// <summary>
        /// Содержит тип текущей <see cref="Mime"/> секции или <see cref="Message"/>.
        /// </summary>    
        public string ContentType
        {
          get
          {
            return (string)Headers["content-type"];
          }
        }
        #endregion
      }
    }

    Класс Message.cs

    namespace Mail
    {
      using System;
      using System.Text;
      using System.Text.RegularExpressions;
      using System.Collections;
      using System.Diagnostics;
    
      using Mail.Providers;
      /// <summary>
      /// Класс, который описывает сообщение, полученное с сервера.  
      /// </summary>
      public class Message : Common, IDisposable
      {
        string _body;
        // Тип тела сообщения.
        BodyTypes _body_type = BodyTypes.Unknown;
        // Массив вложений.
        AttachDescriptor [] _attaches = null;
    
        /// <summary>
        /// Номер сообщения.
        /// </summary>
        public uint Index;
    
    
        /// <summary>
        /// Создание  нового сообщения.
        /// </summary>
        /// <param name="parent">Ссылка на провайдер.</param>
        /// <param name="message">Текст сообщения, которое необходимо проанализировать.</param>
        /// <param name="index">Номер сообщения.</param>
        public Message(Provider parent, string message, uint index) : base(parent, message)
        {
          // Если индекс сообщения меньше нуля, то генерируется исключение типа ArgumentOutOfRangeException
          if (index < 1)
          {
            throw new ArgumentOutOfRangeException("index");
          }
    
          Index = index;
          ParseContentType();
        }
    
        /// <summary>
        /// Вложенные файлы.
        /// </summary>
        public AttachDescriptor [] Attachments
        {
          get
          {
            if (_attaches == null)
            {
              ArrayList al = new ArrayList();
                        GetAllAttachments(ChildMimes, al);
              _attaches = (AttachDescriptor [])al.ToArray(typeof(AttachDescriptor));
            }
    
            return _attaches;
          }
        }
    
        /// <summary>
        /// Получение всех вложений.
        /// </summary>
        /// <param name="mimes"></param>
        void GetAllAttachments(Mime [] mimes, ArrayList al)
        {
          foreach (Mime m in mimes)
          {
            if (m.ChildMimes.Length == 0)
            {
              if (m._attach != null) al.Add(m._attach);
            } 
            else
            {
              GetAllAttachments(m.ChildMimes, al);
            }
          }
        }
      
        // Анализ типа сообщения.
        void ParseContentType()
        {
          if (ContentType == null)
          {
                    throw new ParseException("Определение типа сообщения (Content-Type пуст)");
          }
    
          string type;
          int i = ContentType.IndexOf(";");
          if (i < 0)
          {
            type = ContentType;
          }
          else
          {
                    type = ContentType.Substring(0, i);
          }
          // В зависимости от типа сообщения анализируем текст и выбираем вложения.
          switch(type)
          {
            case "multipart/mixed":
              MultipartMixed();
              break;
    
            case "multipart/alternative":
              MultipartMixed();
              break;
    
            case "multipart/related":
              MultipartMixed();
              break;
    
            case "text/html":
              _body = _message;
              _body_type = BodyTypes.HTML;
              break;
    
            case "text/plain":
              _body = _message;
              _body_type = BodyTypes.Text;
              break;
          }
        }
    
        /// <summary>
            /// Анализирует строку для получения e-mail.    
        /// </summary>
        /// <param name="mail">Строка с адресом</param>
        /// <returns>адрес типа [mail@host.com], [mail@localhost] или [host@123.123.123.123]</returns>
        public string ExtractEmailFromAddress(string mail)
        {
          // mail@(ip)|(host)
          Regex ex = new Regex(@"([a-zA-Z0-9_\-\.]+)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([a-zA-Z0-9\-]+\.?)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)");
          Match m = ex.Match(mail);
          if (!m.Success) 
          {
            throw new ParseException("email не найден.");
          }
    
          return m.ToString();
        }
    
        public void Dispose()
        {
          foreach(AttachDescriptor ad in Attachments)
          {
                    ad.Close();
          }            
    
          _attaches = null;
          _body = null;
          _message = null;
          Headers = null;
          ChildMimes = null;
    
          GC.SuppressFinalize(this);
        }
        /// <summary>
        /// Перегруженный метод ToString. Возвращает информацию о сообщении.
        /// </summary>
        /// <returns></returns>
        public override string ToString()
        {
          StringBuilder sb = new StringBuilder();
    
          sb.AppendFormat("Size: {0}b\r\n", GetSize());
          sb.AppendFormat("From: '{0}', email: '{1}'\r\n", From, FromEmail);
          sb.AppendFormat("Subject: '{0}'\r\n", Subject);
    
          if (Attachments.Length > 0)
          {
            sb.Append("Attachments:\r\n");
    
            foreach(AttachDescriptor ad in Attachments)
            {
              sb.Append("\tName: " + ad.Name + " Size: " + ad.Size + "\r\n");
            }
          }
    
          return sb.ToString();
        }
        // 
        /// <summary>
        /// Возможные типы тела сообщения.
        /// </summary>
        public enum BodyTypes
        {
          Unknown,
                HTML,
          Text
        }
    
        /// <summary>
        /// Возвращение  тела сообщения из MIME.
        /// </summary>
        /// <param name="type">Тип тела сообщения.</param>
        /// <param name="mimes">MIME</param>
        /// <returns></returns>
        string GetBodyFromMime(BodyTypes type, Mime [] mimes)
        {
          foreach (Mime m in mimes)
          {
            if (m.ChildMimes.Length == 0)
            {
              switch(type)
              {
                case BodyTypes.HTML:
                  if (m.ContentType.IndexOf("text/html") > -1)
                  {
                    return m.PreparedBody();
                  }
                  break;
    
                case BodyTypes.Text:
                  if (m.ContentType.IndexOf("text/plain") > -1)
                  {
                    return m.PreparedBody();
                  }
                  break;
              }
            } 
            else
            {
              string r = GetBodyFromMime(type, m.ChildMimes);
              if (r != "") return r;
            }
          }
    
          return "";
        }
    
        /// <summary>
        /// Открытый метод, возвращающий тело сообщения.
        /// </summary>
        /// <param name="type">Тип тела сообщения.</param>
        /// <returns></returns>
        public string GetBody(BodyTypes type)
        {
          if (_body_type == BodyTypes.Unknown)
            return GetBodyFromMime(type, ChildMimes);
          else
            return PreparedString(_body);
    
        }
    
        /// <summary>
        /// Возвращение тела сообщения.
        /// </summary>
        /// <returns></returns>
        public string Text
        {
          get
          {
            string text;
            if (_body_type == BodyTypes.Unknown)
            {
              text = GetBodyFromMime(BodyTypes.Text, ChildMimes);
              if (text == null || text.Trim() == "")
                text = Utils.ExtractTextFromHtml(GetBodyFromMime(BodyTypes.HTML, ChildMimes));
            }
            else
            {
              text = PreparedString(_body);
                        if (_body_type == BodyTypes.HTML) 
                text = Utils.ExtractTextFromHtml(text);
            }
    
            return text.Trim();
          }
        }
    
        #region Common headers
            /// <summary>
            /// Организация.
            /// </summary>
        public string Organization
        {
          get
          {
            return (string)Headers["organization"];
          }
        }
    
        /// <summary>
        /// Копии письма.
        /// </summary>    
        public string CC
        {
          get
          {
            return (string)Headers["cc"];
          }
        }
    
        /// <summary>
        /// Дата сообщения.
        /// </summary>
        public string Date
        {
          get
          {
            return (string)Headers["date"];
          }
        }
    
        /// <summary>
        /// Адрес отправителя.
        /// </summary>
        public string ReturnPath
        {
          get
          {
            return (string)Headers["return-path"];
          }
        }
    
        /// <summary>
        /// Адрес отправителя.
        /// </summary>    
        public string From
        {
          get
          {
                    return (string)Headers["from"];
          }
        }
            /// <summary>
            /// От кого.
            /// </summary>
        public string FromEmail
        {
          get
          {
            return ExtractEmailFromAddress((string)Headers["from"]);
          }
        }
            /// <summary>
            /// Кому
            /// </summary>
        public string To
        {
          get
          {
            return (string)Headers["to"];
          }
        }
            /// <summary>
            /// Тема
            /// </summary>
        public string Subject
        {
          get
          {
            return Utils.WordDecoder((string)Headers["subject"]);
          }
        }
            /// <summary>
            /// Повтор
            /// </summary>
        public string ReplyTo
        {
          get
          {
            return (string)Headers["reply-to"];
          }
        }
        #endregion
      }
    }

    Класс Mime.cs

    //#define _DEBUG
    
    namespace Mail
    {
      using System;
      using System.Diagnostics;
      using System.Text;
      using System.IO;
      using System.Text.RegularExpressions;
      using System.Security.Cryptography;
    
      using Mail.Providers;
    
      public class Mime : Common
      {
        #region DEBUG
        FileStream GetDebugStream()
        {
          return new FileStream(@"C:\trace_mimes.log", FileMode.Append);
        }
        [Conditional("_DEBUG")]
        void Trace(string str)
        {
          FileStream fs = GetDebugStream();
          byte [] b = Encoding.ASCII.GetBytes(str);
          fs.Write(b, 0, b.Length);
          fs.Close();
        }
        #endregion
    
        internal AttachDescriptor _attach = null;
    
        /// <summary>
        /// Конструктор.
        /// </summary>
        /// <param name="pm">Провайдер.</param>
        /// <param name="message">Текст сообщения.</param>
        internal Mime(Provider pm, string message) : base(pm, message)
        {      
                // если MIME не содержит MultipartMixed, то осуществляется попытка  проверки на наличие вложений
          if (!MultipartMixed())
          {
            FindAttachment();
          }
        }
        /// <summary>
        /// Определение  вложения сообщения.
        /// </summary>
        void FindAttachment()
        {
          // Если вложения нет, возвращаемся назад
          if (ContentDisposition == null) 
          {
                    return;
          }
    
          string [] cd = ContentDisposition.Split(new char [] {';'}, 2);
          switch(cd[0].ToLower())
          {
                    case "attachment":
              ExtractAttachment(cd[1]);
              break;
                    
            case "inline":
              throw new CoreException("не реализовано");
    
            default:
              throw new ParseException("Неизвестный ContentDisposition:" + cd[0]);
          }
        }
        /// <summary>
        /// Получение имени вложенного файла.
        /// </summary>
        /// <param name="filename"></param>
        /// <returns></returns>
        string GetAttachmentFilename(string filename)
        {
          Regex r = new Regex("filename=[\\\"]?([^\\r\\\"]+)");
          Match m = r.Match(filename);
          if (!m.Success)
          {
                    return String.Empty;
          }      
    
          return Utils.WordDecoder(m.Groups[1].ToString());
        }
        /// <summary>
        /// Извлечение прикрепленных файлов из сообщения.
        /// </summary>
        /// <param name="filename">Название временного файла.</param>
        void ExtractAttachment(string filename)
        {
          _attach = new AttachDescriptor(GetAttachmentFilename(filename), _pop3.TempDirectory);
    
          switch (TransferEncoding)
          {
            case "base64":
              _attach.DecodeFile(_message, new FromBase64Transform());
              break;
    
            case "quoted-printable":
              _attach.DecodeFile(_message, new FromQuotedPrintableTransform());
              break;
    
            default:
                        Debug.WriteLine("Неизвестный тип кодировки.");
              break;
          }
        }
    
        #region Common headers
        /// <summary>
        /// Возвращение  заголовка content-disposition, сообщающего о вложении.
        /// </summary>
        string ContentDisposition
        {
          get
          {
            return (string)Headers["content-disposition"];
          }
        }
        #endregion
      }
    }

    Отправка сообщений — проект SendMail

    Основной листинг MailSender.cs:

    using System;
    using System.Web.Mail;
    
    namespace Mail
    {
      /// <summary>
      /// Класс, отвечающий за отправку почты.
      /// </summary>
      /// <example>
      /// MailSender mailSender = new MailSender("smtp.someserver.com");
      /// MailMessage message = new MailMessage();
      /// message.From = "from@someserver.com";
      /// message.To = "to@someserver.com";
      /// message.Subject = "subject";
      /// message.Body = "body text";
      /// message.BodyFormat = MailFormat.Text;
      /// mailSender.Send(message);
      /// </example>
      public class MailSender
      {
        private string _server;
        
        /// <summary>
        /// Конструктор.
        /// </summary>
        /// <param name="server">SMTP-сервер.</param>    
        public MailSender(string server)
        {
          this._server = server;      
        }
    
        /// <summary>
        /// Отправка почты.
        /// </summary>
        /// <param name="message">Письмо.</param>
        public void Send(MailMessage message)
        {
          // Инициализируем сервер отправки сообщений.
          SmtpMail.SmtpServer = this._server;
          // Отправляем сообщение.
          SmtpMail.Send(message);
        }
    
        /// <summary>
        /// Отправка почты с паролем.
        /// </summary>
        /// <param name="message">Письмо.</param>
        /// <param name="password">Пароль пользователя.</param>
        public void Send(MailMessage message, string password)
        {
          // Добавляем к сообщению имя пользователя и пароль на тот случай,
          // когда сервер исходящей почты требует аутентификацию.
          message.Fields.Add("http://schemas.microsoft.com/cdo/configuration/smtpauthenticate", 1);
          message.Fields.Add("http://schemas.microsoft.com/cdo/configuration/sendusername", message.From); 
          message.Fields.Add("http://schemas.microsoft.com/cdo/configuration/sendpassword", password);
          // Отправляем сообщение.
          this.Send(message);
        }
      }
    }

    Интерфейс программы Ballet — проект MailApplication.

    Создание новой учетной записи. Форма-контейнер Мастера

    Форма CreateUserWizard представляет собой родительский контейнер для помещения в нее форм — шагов Мастера (см. рис. 3.25)

    using System;
    using System.Drawing;
    using System.Collections;
    using System.ComponentModel;
    using System.Windows.Forms;
    
    namespace MailApplication
    {
      /// <summary>
      /// Summary description for CreateUserWizard.
      /// </summary>
      public class CreateUserWizard : System.Windows.Forms.Form
      {
        /// <summary>
        /// Required designer variable.
        /// </summary>
        private System.ComponentModel.Container components = null;
    
        public CreateUserWizard()
        {
          //
          // Required for Windows Form Designer support
          //
          InitializeComponent();
    
          //
          // TODO: Add any constructor code after InitializeComponent call
          //
        }
    
        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        protected override void Dispose( bool disposing )
        {
          if( disposing )
          {
            if(components != null)
            {
              components.Dispose();
            }
          }
          base.Dispose( disposing );
        }
    
        #region Windows Form Designer generated code
        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
          System.Resources.ResourceManager resources = new System.Resources.ResourceManager(typeof(CreateUserWizard));
          // 
          // CreateUserWizard
          // 
          this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
          this.ClientSize = new System.Drawing.Size(392, 266);
          this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
          this.IsMdiContainer = true;
          this.Name = "CreateUserWizard";
          this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
          this.Text = "Создание новый учетной записи";
          this.Load += new System.EventHandler(this.CreateUserWizard_Load);
    
        }
        #endregion
    
        private void CreateUserWizard_Load(object sender, System.EventArgs e)
        {
          UserIdentity identity = new UserIdentity();      
          CUWStep1 step1 = new CUWStep1(identity);
          step1.MdiParent = this;
          step1.Show();
        }
      }
    }

    Первый шаг Мастера. Форма CUWStep1.cs

    Значения свойства Name элементов управления этой формы приведены на рис. 3.27:

    (рис 3.27) Форма CUWStep1

    Полный листинг формы:

    using System;
    using System.Drawing;
    using System.Collections;
    using System.ComponentModel;
    using System.Windows.Forms;
    
    namespace MailApplication
    {
      /// <summary>
      /// Summary description for CUWStep1.
      /// </summary>
      public class CUWStep1 : System.Windows.Forms.Form
      {
        private UserIdentity identity;
        private System.Windows.Forms.Label lblEmail;
        private System.Windows.Forms.TextBox txbEmail;
        private System.Windows.Forms.Label lblMailSample;
        private System.Windows.Forms.Label lblAliasSample;
        private System.Windows.Forms.TextBox txbAlias;
        private System.Windows.Forms.Label lblAlias;
        private System.Windows.Forms.Button btnNext;
        /// <summary>
        /// Required designer variable.
        /// </summary>
        private System.ComponentModel.Container components = null;
    
        public CUWStep1(UserIdentity identity)
        {      
          InitializeComponent();
    
          this.identity = identity;
        }
    
        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        protected override void Dispose( bool disposing )
        {
          if( disposing )
          {
            if(components != null)
            {
              components.Dispose();
            }
          }
          base.Dispose( disposing );
        }
    
        #region Windows Form Designer generated code
        /// <summary>
        /// Required method for Designer support — do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
          System.Resources.ResourceManager resources = new System.Resources.ResourceManager(typeof(CUWStep1));
          this.lblEmail = new System.Windows.Forms.Label();
          this.txbEmail = new System.Windows.Forms.TextBox();
          this.lblMailSample = new System.Windows.Forms.Label();
          this.lblAliasSample = new System.Windows.Forms.Label();
          this.txbAlias = new System.Windows.Forms.TextBox();
          this.lblAlias = new System.Windows.Forms.Label();
          this.btnNext = new System.Windows.Forms.Button();
          this.SuspendLayout();
          // 
          // lblEmail
          // 
          this.lblEmail.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
            | System.Windows.Forms.AnchorStyles.Right)));
          this.lblEmail.Location = new System.Drawing.Point(24, 16);
          this.lblEmail.Name = "lblEmail";
          this.lblEmail.Size = new System.Drawing.Size(240, 23);
          this.lblEmail.TabIndex = 0;
          this.lblEmail.Text = "Введите адрес электронной почты";
          this.lblEmail.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
          // 
          // txbEmail
          // 
          this.txbEmail.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
            | System.Windows.Forms.AnchorStyles.Right)));
          this.txbEmail.Location = new System.Drawing.Point(24, 48);
          this.txbEmail.Name = "txbEmail";
          this.txbEmail.Size = new System.Drawing.Size(240, 20);
          this.txbEmail.TabIndex = 1;
          this.txbEmail.Text = "";
          // 
          // lblMailSample
          // 
          this.lblMailSample.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
            | System.Windows.Forms.AnchorStyles.Right)));
          this.lblMailSample.ForeColor = System.Drawing.SystemColors.AppWorkspace;
          this.lblMailSample.Location = new System.Drawing.Point(24, 72);
          this.lblMailSample.Name = "lblMailSample";
          this.lblMailSample.Size = new System.Drawing.Size(240, 23);
          this.lblMailSample.TabIndex = 2;
          this.lblMailSample.Text = "Например, address@mail.com";
          this.lblMailSample.TextAlign = System.Drawing.ContentAlignment.TopRight;
          // 
          // lblAliasSample
          // 
          this.lblAliasSample.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
            | System.Windows.Forms.AnchorStyles.Right)));
          this.lblAliasSample.ForeColor = System.Drawing.SystemColors.AppWorkspace;
          this.lblAliasSample.Location = new System.Drawing.Point(26, 160);
          this.lblAliasSample.Name = "lblAliasSample";
          this.lblAliasSample.Size = new System.Drawing.Size(240, 23);
          this.lblAliasSample.TabIndex = 5;
          this.lblAliasSample.Text = "Например, Иван Васильевич";
          this.lblAliasSample.TextAlign = System.Drawing.ContentAlignment.TopRight;
          // 
          // txbAlias
          // 
          this.txbAlias.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
            | System.Windows.Forms.AnchorStyles.Right)));
          this.txbAlias.Location = new System.Drawing.Point(26, 136);
          this.txbAlias.Name = "txbAlias";
          this.txbAlias.Size = new System.Drawing.Size(240, 20);
          this.txbAlias.TabIndex = 2;
          this.txbAlias.Text = "";
          // 
          // lblAlias
          // 
          this.lblAlias.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
            | System.Windows.Forms.AnchorStyles.Right)));
          this.lblAlias.Location = new System.Drawing.Point(26, 104);
          this.lblAlias.Name = "lblAlias";
          this.lblAlias.Size = new System.Drawing.Size(240, 23);
          this.lblAlias.TabIndex = 3;
          this.lblAlias.Text = "Введите ваше имя ";
          this.lblAlias.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
          // 
          // btnNext
          // 
          this.btnNext.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
          this.btnNext.Location = new System.Drawing.Point(192, 192);
          this.btnNext.Name = "btnNext";
          this.btnNext.TabIndex = 3;
          this.btnNext.Text = "Далее";
          this.btnNext.Click += new System.EventHandler(this.btnNext_Click);
          // 
          // CUWStep1
          // 
          this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
          this.ClientSize = new System.Drawing.Size(292, 238);
          this.ControlBox = false;
          this.Controls.Add(this.btnNext);
          this.Controls.Add(this.lblAliasSample);
          this.Controls.Add(this.txbAlias);
          this.Controls.Add(this.txbEmail);
          this.Controls.Add(this.lblAlias);
          this.Controls.Add(this.lblMailSample);
          this.Controls.Add(this.lblEmail);
          this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
          this.Name = "CUWStep1";
          this.Text = "Шаг 1 из 3";
          this.WindowState = System.Windows.Forms.FormWindowState.Maximized;
          this.ResumeLayout(false);
    
        }
        #endregion
    
        private void btnNext_Click(object sender, System.EventArgs e)
        {
          if(txbEmail.Text == "")
          {
            MessageBox.Show("Введите адрес электронной почты.");
            return;
          }
          else
          {
            identity.Alias = txbAlias.Text;
            identity.Mail = txbEmail.Text;
            
            CUWStep2 step2 = new CUWStep2(this.identity);
            step2.MdiParent = this.MdiParent;
            this.Close();
            step2.Show();
          }
        }
    
        
      }
    }

    Второй шаг Мастера. Форма CUWStep2.cs

    Значения свойства Name элементов управления этой формы приведены на рис. 3.28.

    (рис 3.28) Форма CUWStep2

    Полный листинг формы:

    using System;
    using System.Drawing;
    using System.Collections;
    using System.ComponentModel;
    using System.Windows.Forms;
    
    namespace MailApplication
    {
      /// <summary>
      /// Summary description for CUWStep2.
      /// </summary>
      public class CUWStep2 : System.Windows.Forms.Form
      {
        private UserIdentity identity;
        private System.Windows.Forms.Label lblPop3Sample;
        private System.Windows.Forms.TextBox txbPop3;
        private System.Windows.Forms.Label lblPop3;
        private System.Windows.Forms.Label lblPop3PortSample;
        private System.Windows.Forms.TextBox txbPop3Port;
        private System.Windows.Forms.Label lblPop3Port;
        private System.Windows.Forms.Button btnNext;
        /// <summary>
        /// Required designer variable.
        /// </summary>
        private System.ComponentModel.Container components = null;
    
        public CUWStep2(UserIdentity identity)
        {      
          InitializeComponent();
    
          this.identity = identity;
        }
    
        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        protected override void Dispose( bool disposing )
        {
          if( disposing )
          {
            if(components != null)
            {
              components.Dispose();
            }
          }
          base.Dispose( disposing );
        }
    
        #region Windows Form Designer generated code
        /// <summary>
        /// Required method for Designer support — do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
          System.Resources.ResourceManager resources = new System.Resources.ResourceManager(typeof(CUWStep2));
          this.lblPop3Sample = new System.Windows.Forms.Label();
          this.txbPop3 = new System.Windows.Forms.TextBox();
          this.lblPop3 = new System.Windows.Forms.Label();
          this.lblPop3PortSample = new System.Windows.Forms.Label();
          this.txbPop3Port = new System.Windows.Forms.TextBox();
          this.lblPop3Port = new System.Windows.Forms.Label();
          this.btnNext = new System.Windows.Forms.Button();
          this.SuspendLayout();
          // 
          // lblPop3Sample
          // 
          this.lblPop3Sample.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
            | System.Windows.Forms.AnchorStyles.Right)));
          this.lblPop3Sample.ForeColor = System.Drawing.SystemColors.AppWorkspace;
          this.lblPop3Sample.Location = new System.Drawing.Point(26, 64);
          this.lblPop3Sample.Name = "lblPop3Sample";
          this.lblPop3Sample.Size = new System.Drawing.Size(240, 23);
          this.lblPop3Sample.TabIndex = 5;
          this.lblPop3Sample.Text = "Например, pop3.mail.com";
          this.lblPop3Sample.TextAlign = System.Drawing.ContentAlignment.TopRight;
          // 
          // txbPop3
          // 
          this.txbPop3.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
            | System.Windows.Forms.AnchorStyles.Right)));
          this.txbPop3.Location = new System.Drawing.Point(26, 40);
          this.txbPop3.Name = "txbPop3";
          this.txbPop3.Size = new System.Drawing.Size(240, 20);
          this.txbPop3.TabIndex = 4;
          this.txbPop3.Text = "";
          // 
          // lblPop3
          // 
          this.lblPop3.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
            | System.Windows.Forms.AnchorStyles.Right)));
          this.lblPop3.Location = new System.Drawing.Point(26, 8);
          this.lblPop3.Name = "lblPop3";
          this.lblPop3.Size = new System.Drawing.Size(240, 23);
          this.lblPop3.TabIndex = 3;
          this.lblPop3.Text = "Введите адрес  сервера POP3:";
          this.lblPop3.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
          // 
          // lblPop3PortSample
          // 
          this.lblPop3PortSample.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
            | System.Windows.Forms.AnchorStyles.Right)));
          this.lblPop3PortSample.ForeColor = System.Drawing.SystemColors.AppWorkspace;
          this.lblPop3PortSample.Location = new System.Drawing.Point(26, 160);
          this.lblPop3PortSample.Name = "lblPop3PortSample";
          this.lblPop3PortSample.Size = new System.Drawing.Size(240, 23);
          this.lblPop3PortSample.TabIndex = 8;
          this.lblPop3PortSample.Text = "Например, 110";
          this.lblPop3PortSample.TextAlign = System.Drawing.ContentAlignment.TopRight;
          // 
          // txbPop3Port
          // 
          this.txbPop3Port.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
            | System.Windows.Forms.AnchorStyles.Right)));
          this.txbPop3Port.Location = new System.Drawing.Point(26, 136);
          this.txbPop3Port.Name = "txbPop3Port";
          this.txbPop3Port.Size = new System.Drawing.Size(240, 20);
          this.txbPop3Port.TabIndex = 7;
          this.txbPop3Port.Text = "110";
          // 
          // lblPop3Port
          // 
          this.lblPop3Port.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
            | System.Windows.Forms.AnchorStyles.Right)));
          this.lblPop3Port.Location = new System.Drawing.Point(26, 104);
          this.lblPop3Port.Name = "lblPop3Port";
          this.lblPop3Port.Size = new System.Drawing.Size(240, 23);
          this.lblPop3Port.TabIndex = 6;
          this.lblPop3Port.Text = "Укажите почтовый порт:";
          this.lblPop3Port.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
          // 
          // btnNext
          // 
          this.btnNext.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
          this.btnNext.Location = new System.Drawing.Point(192, 200);
          this.btnNext.Name = "btnNext";
          this.btnNext.TabIndex = 9;
          this.btnNext.Text = "Далее";
          this.btnNext.Click += new System.EventHandler(this.btnNext_Click);
          // 
          // CUWStep2
          // 
          this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
          this.ClientSize = new System.Drawing.Size(292, 238);
          this.Controls.Add(this.btnNext);
          this.Controls.Add(this.lblPop3PortSample);
          this.Controls.Add(this.txbPop3Port);
          this.Controls.Add(this.lblPop3Port);
          this.Controls.Add(this.lblPop3Sample);
          this.Controls.Add(this.txbPop3);
          this.Controls.Add(this.lblPop3);
          this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
          this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
          this.Name = "CUWStep2";
          this.Text = "Шаг 2 из 3";
          this.WindowState = System.Windows.Forms.FormWindowState.Maximized;
          this.ResumeLayout(false);
    
        }
        #endregion
    
        private void btnNext_Click(object sender, System.EventArgs e)
        {
          if(txbPop3.Text == "")
          {
            MessageBox.Show("Введите адрес сервера POP3");
          }
          else
          {
            this.identity.Pop3 = txbPop3.Text;
            try
            {
              //Преобразовываем введенное значение в тип Int32 
              this.identity.Pop3Port = Int32.Parse(txbPop3Port.Text);
              CUWStep3 step3 = new CUWStep3(this.identity);
              step3.MdiParent = this.MdiParent;
              this.Close();
              step3.Show();
            }
            catch(Exception)
            {
              MessageBox.Show("Значение порта должно быть числом");
            }
          }
    
        }
      }
    }

    Третий шаг Мастера. Форма CUWStep3.cs

    Значения свойства Name элементов управления этой формы приведены на рис. 3.29.

    (рис 3.29) Форма CUWStep3

    Полный листинг формы:

    using System;
    using System.Drawing;
    using System.Collections;
    using System.ComponentModel;
    using System.Windows.Forms;
    using System.Threading;
    using System.Security.Principal;
    
    namespace MailApplication
    {
      /// <summary>
      /// Summary description for CUWStep3.
      /// </summary>
      public class CUWStep3 : System.Windows.Forms.Form
      {
        private UserIdentity identity;
        private System.Windows.Forms.Label lblSmtpSample;
        private System.Windows.Forms.TextBox txbSmtp;
        private System.Windows.Forms.Label lblSmtp;
        private System.Windows.Forms.Button btnFinish;
        /// <summary>
        /// Required designer variable.
        /// </summary>
        private System.ComponentModel.Container components = null;
    
        public CUWStep3(UserIdentity identity)
        {
          InitializeComponent();
          this.identity = identity;
        }
    
        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        protected override void Dispose( bool disposing )
        {
          if( disposing )
          {
            if(components != null)
            {
              components.Dispose();
            }
          }
          base.Dispose( disposing );
        }
    
        #region Windows Form Designer generated code
        /// <summary>
        /// Required method for Designer support — do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
          System.Resources.ResourceManager resources = new System.Resources.ResourceManager(typeof(CUWStep3));
          this.lblSmtpSample = new System.Windows.Forms.Label();
          this.txbSmtp = new System.Windows.Forms.TextBox();
          this.lblSmtp = new System.Windows.Forms.Label();
          this.btnFinish = new System.Windows.Forms.Button();
          this.SuspendLayout();
          // 
          // lblSmtpSample
          // 
          this.lblSmtpSample.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
            | System.Windows.Forms.AnchorStyles.Right)));
          this.lblSmtpSample.ForeColor = System.Drawing.SystemColors.AppWorkspace;
          this.lblSmtpSample.Location = new System.Drawing.Point(26, 72);
          this.lblSmtpSample.Name = "lblSmtpSample";
          this.lblSmtpSample.Size = new System.Drawing.Size(240, 23);
          this.lblSmtpSample.TabIndex = 8;
          this.lblSmtpSample.Text = "Например, smtp.mail.com";
          this.lblSmtpSample.TextAlign = System.Drawing.ContentAlignment.TopRight;
          // 
          // txbSmtp
          // 
          this.txbSmtp.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
            | System.Windows.Forms.AnchorStyles.Right)));
          this.txbSmtp.Location = new System.Drawing.Point(26, 48);
          this.txbSmtp.Name = "txbSmtp";
          this.txbSmtp.Size = new System.Drawing.Size(240, 20);
          this.txbSmtp.TabIndex = 7;
          this.txbSmtp.Text = "";
          // 
          // lblSmtp
          // 
          this.lblSmtp.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
            | System.Windows.Forms.AnchorStyles.Right)));
          this.lblSmtp.Location = new System.Drawing.Point(26, 16);
          this.lblSmtp.Name = "lblSmtp";
          this.lblSmtp.Size = new System.Drawing.Size(240, 23);
          this.lblSmtp.TabIndex = 6;
          this.lblSmtp.Text = "Введите адрес SMTP-сервера:";
          this.lblSmtp.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
          // 
          // btnFinish
          // 
          this.btnFinish.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
          this.btnFinish.Location = new System.Drawing.Point(200, 208);
          this.btnFinish.Name = "btnFinish";
          this.btnFinish.TabIndex = 9;
          this.btnFinish.Text = "Готово";
          this.btnFinish.Click += new System.EventHandler(this.btnFinish_Click);
          // 
          // CUWStep3
          // 
          this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
          this.ClientSize = new System.Drawing.Size(292, 266);
          this.Controls.Add(this.btnFinish);
          this.Controls.Add(this.lblSmtpSample);
          this.Controls.Add(this.txbSmtp);
          this.Controls.Add(this.lblSmtp);
          this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
          this.Name = "CUWStep3";
          this.Text = "Шаг 3 из 3";
          this.WindowState = System.Windows.Forms.FormWindowState.Maximized;
          this.ResumeLayout(false);
    
        }
        #endregion
    
        private void btnFinish_Click(object sender, System.EventArgs e)
        {
          if(txbSmtp.Text != "")
          {
            this.identity.Smtp = txbSmtp.Text;
            //Закрываем текущую форму
            this.Close();
            Thread.CurrentPrincipal = new GenericPrincipal(this.identity, new string[]{"user"});
            this.identity.Dispose();
            //Закрываем родительскую форму CreateUserWizard  
            Form.ActiveForm.Close();
            
          }
          else
          {
            MessageBox.Show("Введите адрес сервера SMTP");
          }
        }
    
      
      }
    }

    Главная форма mainForm.cs

    Главная форма программы представляет собой контейнер для других форм и поэтому содержит сравнительно мало элементов управления. Значения свойства Name элементов управления приведены на рис. 3.30.

    (рис 3.30) Форма mainForm

    Полный листинг формы:

    using System;
    using System.Drawing;
    using System.Collections;
    using System.ComponentModel;
    using System.Windows.Forms;
    using System.Data;
    using System.Threading;
    using System.Security.Principal;
    
    namespace MailApplication
    {
      /// <summary>
      /// Summary description for Form1.
      /// </summary>
      public class mainForm : System.Windows.Forms.Form
      {
        private System.Windows.Forms.MainMenu mainMenu;
        private System.Windows.Forms.MenuItem itemFile;
        private System.Windows.Forms.MenuItem itemUsers;
        private System.Windows.Forms.MenuItem itemNewUser;
        private System.Windows.Forms.MenuItem itemExit;
        private System.Windows.Forms.MenuItem itemEvent;
        private System.Windows.Forms.MenuItem itemGet;
        private System.Windows.Forms.MenuItem itemSend;
        private System.Windows.Forms.MenuItem itemSetting;
        /// <summary>
        /// Required designer variable.
        /// </summary>
        private System.ComponentModel.Container components = null;
    
        public mainForm()
        {
          //
          // Required for Windows Form Designer support
          //
          InitializeComponent();
    
          //
          // TODO: Add any constructor code after InitializeComponent call
          //
        }
    
        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        protected override void Dispose( bool disposing )
        {
          if( disposing )
          {
            if (components != null) 
            {
              components.Dispose();
            }
          }
          base.Dispose( disposing );
        }
    
        #region Windows Form Designer generated code
        /// <summary>
        /// Required method for Designer support — do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
          System.Resources.ResourceManager resources = new System.Resources.ResourceManager(typeof(mainForm));
          this.mainMenu = new System.Windows.Forms.MainMenu();
          this.itemFile = new System.Windows.Forms.MenuItem();
          this.itemNewUser = new System.Windows.Forms.MenuItem();
          this.itemUsers = new System.Windows.Forms.MenuItem();
          this.itemExit = new System.Windows.Forms.MenuItem();
          this.itemEvent = new System.Windows.Forms.MenuItem();
          this.itemGet = new System.Windows.Forms.MenuItem();
          this.itemSend = new System.Windows.Forms.MenuItem();
          this.itemSetting = new System.Windows.Forms.MenuItem();
          // 
          // mainMenu
          // 
          this.mainMenu.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] {
                                               this.itemFile,
                                               this.itemEvent});
          // 
          // itemFile
          // 
          this.itemFile.Index = 0;
          this.itemFile.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] {
                                               this.itemNewUser,
                                               this.itemUsers,
                                               this.itemExit});
          this.itemFile.Text = "Файл";
          // 
          // itemNewUser
          // 
          this.itemNewUser.Index = 0;
          this.itemNewUser.Shortcut = System.Windows.Forms.Shortcut.CtrlN;
          this.itemNewUser.Text = "Новый пользователь";
          this.itemNewUser.Click += new System.EventHandler(this.itemNewUser_Click);
          // 
          // itemUsers
          // 
          this.itemUsers.Index = 1;
          this.itemUsers.Shortcut = System.Windows.Forms.Shortcut.CtrlL;
          this.itemUsers.Text = "Смена пользователя";
          this.itemUsers.Click += new System.EventHandler(this.itemUsers_Click);
          // 
          // itemExit
          // 
          this.itemExit.Index = 2;
          this.itemExit.Shortcut = System.Windows.Forms.Shortcut.AltF4;
          this.itemExit.Text = "Выход";
          this.itemExit.Click += new System.EventHandler(this.itemExit_Click);
          // 
          // itemEvent
          // 
          this.itemEvent.Enabled = false;
          this.itemEvent.Index = 1;
          this.itemEvent.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] {
                                                this.itemGet,
                                                this.itemSend,
                                                this.itemSetting});
          this.itemEvent.Text = "Действия";
          // 
          // itemGet
          // 
          this.itemGet.Index = 0;
          this.itemGet.Shortcut = System.Windows.Forms.Shortcut.CtrlG;
          this.itemGet.Text = "Получить почту";
          this.itemGet.Click += new System.EventHandler(this.itemGet_Click);
          // 
          // itemSend
          // 
          this.itemSend.Index = 1;
          this.itemSend.Shortcut = System.Windows.Forms.Shortcut.CtrlS;
          this.itemSend.Text = "Отправить письмо";
          this.itemSend.Click += new System.EventHandler(this.itemSend_Click);
          // 
          // itemSetting
          // 
          this.itemSetting.Index = 2;
          this.itemSetting.Shortcut = System.Windows.Forms.Shortcut.CtrlO;
          this.itemSetting.Text = "Настройки";
          this.itemSetting.Visible = false;
          // 
          // mainForm
          // 
          this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
          this.ClientSize = new System.Drawing.Size(792, 545);
          this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
          this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
          this.IsMdiContainer = true;
          this.Menu = this.mainMenu;
          this.Name = "mainForm";
          this.Text = "Ballet";
          this.Closing += new System.ComponentModel.CancelEventHandler(this.mainForm_Closing);
          this.Load += new System.EventHandler(this.itemUsers_Click);
    
        }
        #endregion
    
        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        [STAThread]
        static void Main() 
        {
          Application.Run(new mainForm());
        }
    
        private void itemExit_Click(object sender, System.EventArgs e)
        {
          this.Close();
        }
    
        private void itemUsers_Click(object sender, System.EventArgs e)
        {
          selectUser select = new selectUser();
          if(select.ShowDialog() != DialogResult.OK)
            //Запускаем главную форму.
            return;
          if(Thread.CurrentPrincipal.Identity is UserIdentity)
            ((UserIdentity)Thread.CurrentPrincipal.Identity).Dispose();
          string userName = select.lstViewUsers.SelectedItems[0].Text;      
          UserIdentity identity = new UserIdentity(userName);      
          Thread.CurrentPrincipal = new GenericPrincipal(identity, new string[]{"user"});
          //Вызываем метод ActivateEventItem
          this.ActivateEventItem();
        }
    
        private void ActivateEventItem()
        {
          //Включаем доступность пункта меню "Действия".
          this.itemEvent.Enabled = true;
        }
    
        private void itemNewUser_Click(object sender, System.EventArgs e)
        {
          //Создаем экземпляр wizard формы CreateUserWizard
          CreateUserWizard wizard = new CreateUserWizard();
          //Показываем форму:
          wizard.ShowDialog();
          if(Thread.CurrentPrincipal != null)
            this.ActivateEventItem();
        }
    
        private void mainForm_Closing(object sender, System.ComponentModel.CancelEventArgs e)
        {
          if(Thread.CurrentPrincipal.Identity is UserIdentity)
            ((UserIdentity)Thread.CurrentPrincipal.Identity).Dispose();
        }
    
        private void itemSend_Click(object sender, System.EventArgs e)
        {      
          PasswordPromt pass = new PasswordPromt();
          if(pass.ShowDialog() != DialogResult.OK)
            return;
          SendMessage send = new SendMessage();
          send.MdiParent = this;
          send.Show();
        }
    
        private void itemGet_Click(object sender, System.EventArgs e)
        {
          PasswordPromt pass = new PasswordPromt();
          if(pass.ShowDialog() != DialogResult.OK)
            return;
          MessageList list = new MessageList();
          list.MdiParent = this;
          list.Show();
        }
    
        
    
        
      }
    }

    Форма списка сообщений MessageList.cs

    Значения свойства Name элементов управления этой формы приведены на рис. 3.31.

    (рис 3.31) Форма MessageList

    Полный листинг формы:

    using System;
    using System.Drawing;
    using System.Collections;
    using System.ComponentModel;
    using System.Windows.Forms;
    
    namespace MailApplication
    {
      /// <summary>
      /// Summary description for MessageList.
      /// </summary>
      public class MessageList : System.Windows.Forms.Form
      {
        private Mail.Providers.Pop3 mail;
        private UserIdentity identity;
        private System.Windows.Forms.ListView lstViewMessages;
        private System.Windows.Forms.ColumnHeader colFrom;
        private System.Windows.Forms.ColumnHeader colSubject;
        private System.Windows.Forms.ColumnHeader colDate;
        private System.Windows.Forms.ImageList imageListIcons;
        private System.Windows.Forms.ColumnHeader colIcon;
        private System.Windows.Forms.Label lblMessagesCount;
        private System.Windows.Forms.Panel pnlPages;
        private System.ComponentModel.IContainer components;
    
        public MessageList()
        {
          InitializeComponent();
          
          identity = (UserIdentity)System.Threading.Thread.CurrentPrincipal.Identity;
          // Создание объекта POP3. 
          if(identity.Pop3Port == -1)
            mail = new Mail.Providers.Pop3(identity.Pop3);
          else
            mail = new Mail.Providers.Pop3(identity.Pop3, identity.Pop3Port);
        }
    
        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        protected override void Dispose( bool disposing )
        {
          if( disposing )
          {
            if(components != null)
            {
              components.Dispose();
            }
          }
          base.Dispose( disposing );
        }
    
        #region Windows Form Designer generated code
        /// <summary>
        /// Required method for Designer support — do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
          this.components = new System.ComponentModel.Container();
          System.Resources.ResourceManager resources = new System.Resources.ResourceManager(typeof(MessageList));
          this.lstViewMessages = new System.Windows.Forms.ListView();
          this.colFrom = new System.Windows.Forms.ColumnHeader();
          this.colSubject = new System.Windows.Forms.ColumnHeader();
          this.colDate = new System.Windows.Forms.ColumnHeader();
          this.imageListIcons = new System.Windows.Forms.ImageList(this.components);
          this.colIcon = new System.Windows.Forms.ColumnHeader();
          this.lblMessagesCount = new System.Windows.Forms.Label();
          this.pnlPages = new System.Windows.Forms.Panel();
          this.SuspendLayout();
          // 
          // lstViewMessages
          // 
          this.lstViewMessages.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
            | System.Windows.Forms.AnchorStyles.Right)));
          this.lstViewMessages.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] {
                                                    this.colIcon,
                                                    this.colFrom,
                                                    this.colSubject,
                                                    this.colDate});
          this.lstViewMessages.Cursor = System.Windows.Forms.Cursors.Hand;
          this.lstViewMessages.FullRowSelect = true;
          this.lstViewMessages.GridLines = true;
          this.lstViewMessages.Location = new System.Drawing.Point(16, 40);
          this.lstViewMessages.MultiSelect = false;
          this.lstViewMessages.Name = "lstViewMessages";
          this.lstViewMessages.Size = new System.Drawing.Size(632, 352);
          this.lstViewMessages.SmallImageList = this.imageListIcons;
          this.lstViewMessages.TabIndex = 0;
          this.lstViewMessages.View = System.Windows.Forms.View.Details;
          this.lstViewMessages.Click += new System.EventHandler(this.lstViewMessages_Click);
          // 
          // colFrom
          // 
          this.colFrom.Text = "От";
          this.colFrom.Width = 177;
          // 
          // colSubject
          // 
          this.colSubject.Text = "Тема";
          this.colSubject.Width = 306;
          // 
          // colDate
          // 
          this.colDate.Text = "Дата";
          this.colDate.Width = 106;
          // 
          // imageListIcons
          // 
          this.imageListIcons.ImageSize = new System.Drawing.Size(16, 16);
          this.imageListIcons.ImageStream = ((System.Windows.Forms.ImageListStreamer)(resources.GetObject("imageListIcons.ImageStream")));
          this.imageListIcons.TransparentColor = System.Drawing.Color.Transparent;
          // 
          // colIcon
          // 
          this.colIcon.Text = "#";
          this.colIcon.Width = 39;
          // 
          // lblMessagesCount
          // 
          this.lblMessagesCount.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
            | System.Windows.Forms.AnchorStyles.Right)));
          this.lblMessagesCount.Location = new System.Drawing.Point(16, 8);
          this.lblMessagesCount.Name = "lblMessagesCount";
          this.lblMessagesCount.Size = new System.Drawing.Size(456, 23);
          this.lblMessagesCount.TabIndex = 1;
          this.lblMessagesCount.Text = "Писем в почтовом ящике: ";
          this.lblMessagesCount.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
          // 
          // pnlPages
          // 
          this.pnlPages.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left) 
            | System.Windows.Forms.AnchorStyles.Right)));
          this.pnlPages.Location = new System.Drawing.Point(16, 400);
          this.pnlPages.Name = "pnlPages";
          this.pnlPages.Size = new System.Drawing.Size(632, 32);
          this.pnlPages.TabIndex = 2;
          // 
          // MessageList
          // 
          this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
          this.ClientSize = new System.Drawing.Size(664, 438);
          this.Controls.Add(this.pnlPages);
          this.Controls.Add(this.lblMessagesCount);
          this.Controls.Add(this.lstViewMessages);
          this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
          this.Name = "MessageList";
          this.Text = "Список сообщений";
          this.WindowState = System.Windows.Forms.FormWindowState.Maximized;
          this.Load += new System.EventHandler(this.MessageList_Load);
          this.ResumeLayout(false);
    
        }
        #endregion
        
        private void MessageList_Load(object sender, System.EventArgs e)
        {
          try
          {  
            // Вход в почтовый сервер.
            mail.LogIn(identity.Name, identity.Password);
            // Отображение количества сообщений.
            lblMessagesCount.Text += mail.NumberOfMessages.ToString();
            this.LoadCurrentPageMessages(1);
            this.DrawPages(1);
          }
          catch(Exception ex)
          {
            MessageBox.Show("При выполнении подключения возникла ошибка: " + ex.Message);
          }      
        }
        /// <summary>
        /// Прорисовывает листинг страниц.
        /// </summary>
        /// <param name="currentPageIndex">Номер текущей страницы.</param>
        void DrawPages(uint currentPageIndex)
        {
          // Очищаем контейнер.
          pnlPages.Controls.Clear();
          uint messagesPerPage = 20;
          uint pagesCount = (uint)(mail.NumberOfMessages / messagesPerPage);      
          // Отображаем номера существующих страниц.
          for(uint i = 1; i <= pagesCount; i++)
          {
            LinkLabel page = new LinkLabel();
            page.Text = i.ToString();
            page.Tag = i;
            page.Click += new EventHandler(page_Click);
            if(i == currentPageIndex)
              page.ForeColor = Color.Black;
            page.Size = new Size(20, 20);
            page.Location = new Point(30 * (int)i, 5);
            pnlPages.Controls.Add(page);
          }
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void page_Click(object sender, EventArgs e)
        {
          uint newPageIndex = Convert.ToUInt32(((LinkLabel)sender).Tag);
          this.LoadCurrentPageMessages(newPageIndex);
          this.DrawPages(newPageIndex);
        }
    
        /// <summary>
        /// Отображает сообщения текущей страницы.
        /// </summary>
        /// <param name="currentPageIndex">Номер текущей страницы.</param>
        void LoadCurrentPageMessages(uint currentPageIndex)
        {
          // Количество сообщений на странице.
          uint messagesPerPage = 20;
          // Индекс первого сообщения на странице.
          uint startIndex = mail.NumberOfMessages — messagesPerPage * currentPageIndex;
          // Индекс последнего сообщения на странице.
          uint finishIndex = startIndex + 20;
          // Загрузка заголовков сообщений.
          for(uint currentMessageIndex = startIndex + 1;
            currentMessageIndex <= finishIndex; currentMessageIndex++)
          {
            Mail.Message msg = null;        
            try
            {
              // Попытка загрузки заголовков сообщения.
              msg = mail.GetMessageHeader(currentMessageIndex, 0);
            }
            catch(Exception ex)
            {
              // Отображение возникшей ошибки.
              MessageBox.Show("При загрузке заголовков сообщения возникла ошибка. Номер сообщения: " +
                currentMessageIndex + "; Текст ошибки: " + ex.Message);
            }
            // Если возникла ошибка, то пропускаем текущее сообщение.
            if(msg == null)
              continue;
            // Отображение информации о сообщении.
            ListViewItem item = new ListViewItem(
              new string[]{currentMessageIndex.ToString(), msg.FromEmail, msg.Subject, msg.Date},
              0);
            item.Tag = currentMessageIndex;
            lstViewMessages.Items.Add(item);
          }
        }
    
    
        private void lstViewMessages_Click(object sender, System.EventArgs e)
        {
          try
          {
            // Получение номера выделенного сообщения.
            uint messageIndex = Convert.ToUInt32(lstViewMessages.SelectedItems[0].Tag);
            // Загрузка сообщения с сервера.
            Mail.Message msg = mail.GetMessage(messageIndex);
            // Отображение сообщения.
            ViewMessage messageViewer = new ViewMessage(msg);
            messageViewer.ShowDialog();
          }
          catch(Exception ex)
          {
            MessageBox.Show("Во время загрузки сообщения произошла следующая ошибка: " + ex.Message);
          }
        }
    
      }
    }

    Форма ввода пароля PasswordPromt.cs

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

    (рис 3.32) Форма PasswordPromt.

    Полный листинг формы:

    using System;
    using System.Drawing;
    using System.Collections;
    using System.ComponentModel;
    using System.Windows.Forms;
    
    namespace MailApplication
    {
      /// <summary>
      /// Summary description for PasswordPromt.
      /// </summary>
      public class PasswordPromt : System.Windows.Forms.Form
      {
        private System.Windows.Forms.Label lblPassword;
        private System.Windows.Forms.TextBox txbPassword;
        private System.Windows.Forms.Button btnSubmit;
        /// <summary>
        /// Required designer variable.
        /// </summary>
        private System.ComponentModel.Container components = null;
    
        public PasswordPromt()
        {
          //
          // Required for Windows Form Designer support
          //
          InitializeComponent();
    
          //
          // TODO: Add any constructor code after InitializeComponent call
          //
        }
    
        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        protected override void Dispose( bool disposing )
        {
          if( disposing )
          {
            if(components != null)
            {
              components.Dispose();
            }
          }
          base.Dispose( disposing );
        }
    
        #region Windows Form Designer generated code
        /// <summary>
        /// Required method for Designer support — do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
          System.Resources.ResourceManager resources = new System.Resources.ResourceManager(typeof(PasswordPromt));
          this.lblPassword = new System.Windows.Forms.Label();
          this.txbPassword = new System.Windows.Forms.TextBox();
          this.btnSubmit = new System.Windows.Forms.Button();
          this.SuspendLayout();
          // 
          // lblPassword
          // 
          this.lblPassword.Location = new System.Drawing.Point(16, 8);
          this.lblPassword.Name = "lblPassword";
          this.lblPassword.Size = new System.Drawing.Size(296, 23);
          this.lblPassword.TabIndex = 0;
          this.lblPassword.Text = "Введите пароль от почтового ящика";
          this.lblPassword.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
          // 
          // txbPassword
          // 
          this.txbPassword.Location = new System.Drawing.Point(16, 40);
          this.txbPassword.Name = "txbPassword";
          this.txbPassword.PasswordChar = '*';
          this.txbPassword.Size = new System.Drawing.Size(296, 20);
          this.txbPassword.TabIndex = 1;
          this.txbPassword.Text = "";
          // 
          // btnSubmit
          // 
          this.btnSubmit.Location = new System.Drawing.Point(240, 72);
          this.btnSubmit.Name = "btnSubmit";
          this.btnSubmit.TabIndex = 2;
          this.btnSubmit.Text = "ОК";
          this.btnSubmit.Click += new System.EventHandler(this.btnSubmit_Click);
          // 
          // PasswordPromt
          // 
          this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
          this.ClientSize = new System.Drawing.Size(328, 110);
          this.Controls.Add(this.btnSubmit);
          this.Controls.Add(this.txbPassword);
          this.Controls.Add(this.lblPassword);
          this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedToolWindow;
          this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
          this.MaximizeBox = false;
          this.MinimizeBox = false;
          this.Name = "PasswordPromt";
          this.Text = "Запрос пароля";
          this.ResumeLayout(false);
        }
        #endregion
    
        private void btnSubmit_Click(object sender, System.EventArgs e)
        {
          if(txbPassword.Text == "")
          {
            MessageBox.Show("Пароль не может быть пустым");
          }
          else
          {
            this.DialogResult = DialogResult.OK;
            ((UserIdentity)System.Threading.Thread.CurrentPrincipal.Identity).Password = txbPassword.Text;
            this.Close();
          }
        }
      }
    }

    Форма выбора пользователя selectUser.cs

    Форма выбора пользователя появляется при запуске программы, она также используется для смены пользователя. Значения свойства Name элементов управления этой формы приведены на рис. 3.33:

    (рис 3.33) Форма selectUser

    Полный листинг формы:

    using System;
    using System.Drawing;
    using System.Collections;
    using System.ComponentModel;
    using System.Windows.Forms;
    using System.IO;
    
    namespace MailApplication
    {
      /// <summary>
      /// Summary description for selectUser.
      /// </summary>
      public class selectUser : System.Windows.Forms.Form
      {
        public System.Windows.Forms.ListView lstViewUsers;
        private System.Windows.Forms.Button btnCancel;
        private System.Windows.Forms.Button btnSelect;
        private System.Windows.Forms.Label lblUserSelect;
        private System.Windows.Forms.ImageList imgLstUser;
        private System.Windows.Forms.ColumnHeader colUserName;
        private System.ComponentModel.IContainer components;
    
        public selectUser()
        {
          //
          // Required for Windows Form Designer support
          //
          InitializeComponent();
    
          //
          // TODO: Add any constructor code after InitializeComponent call
          //
        }
    
        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        protected override void Dispose( bool disposing )
        {
          if( disposing )
          {
            if(components != null)
            {
              components.Dispose();
            }
          }
          base.Dispose( disposing );
        }
    
        #region Windows Form Designer generated code
        /// <summary>
        /// Required method for Designer support — do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
          this.components = new System.ComponentModel.Container();
          System.Resources.ResourceManager resources = new System.Resources.ResourceManager(typeof(selectUser));
          this.lstViewUsers = new System.Windows.Forms.ListView();
          this.colUserName = new System.Windows.Forms.ColumnHeader();
          this.imgLstUser = new System.Windows.Forms.ImageList(this.components);
          this.btnCancel = new System.Windows.Forms.Button();
          this.btnSelect = new System.Windows.Forms.Button();
          this.lblUserSelect = new System.Windows.Forms.Label();
          this.SuspendLayout();
          // 
          // lstViewUsers
          // 
          this.lstViewUsers.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] {
                                                   this.colUserName});
          this.lstViewUsers.Cursor = System.Windows.Forms.Cursors.Hand;
          this.lstViewUsers.GridLines = true;
          this.lstViewUsers.Location = new System.Drawing.Point(8, 40);
          this.lstViewUsers.MultiSelect = false;
          this.lstViewUsers.Name = "lstViewUsers";
          this.lstViewUsers.Size = new System.Drawing.Size(272, 176);
          this.lstViewUsers.SmallImageList = this.imgLstUser;
          this.lstViewUsers.TabIndex = 0;
          this.lstViewUsers.View = System.Windows.Forms.View.Details;
          // 
          // colUserName
          // 
          this.colUserName.Text = "Имя пользователя";
          this.colUserName.Width = 268;
          // 
          // imgLstUser
          // 
          this.imgLstUser.ImageSize = new System.Drawing.Size(16, 16);
          this.imgLstUser.ImageStream = ((System.Windows.Forms.ImageListStreamer)(resources.GetObject("imgLstUser.ImageStream")));
          this.imgLstUser.TransparentColor = System.Drawing.Color.Transparent;
          // 
          // btnCancel
          // 
          this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel;
          this.btnCancel.Location = new System.Drawing.Point(200, 232);
          this.btnCancel.Name = "btnCancel";
          this.btnCancel.TabIndex = 1;
          this.btnCancel.Text = "Отмена";
          this.btnCancel.Click += new System.EventHandler(this.btnCancel_Click);
          // 
          // btnSelect
          // 
          this.btnSelect.Location = new System.Drawing.Point(128, 232);
          this.btnSelect.Name = "btnSelect";
          this.btnSelect.TabIndex = 2;
          this.btnSelect.Text = "Выбор";
          this.btnSelect.Click += new System.EventHandler(this.btnSelect_Click);
          // 
          // lblUserSelect
          // 
          this.lblUserSelect.Location = new System.Drawing.Point(8, 8);
          this.lblUserSelect.Name = "lblUserSelect";
          this.lblUserSelect.Size = new System.Drawing.Size(272, 23);
          this.lblUserSelect.TabIndex = 3;
          this.lblUserSelect.Text = "Выберите пользователя из списка:";
          this.lblUserSelect.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
          // 
          // selectUser
          // 
          this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
          this.CancelButton = this.btnCancel;
          this.ClientSize = new System.Drawing.Size(292, 266);
          this.Controls.Add(this.lblUserSelect);
          this.Controls.Add(this.btnSelect);
          this.Controls.Add(this.btnCancel);
          this.Controls.Add(this.lstViewUsers);
          this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
          this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
          this.Name = "selectUser";
          this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
          this.Text = "Выбор пользователя";
          this.Load += new System.EventHandler(this.selectUser_Load);
          this.ResumeLayout(false);
    
        }
        #endregion
    
        private void selectUser_Load(object sender, System.EventArgs e)
        {
          DirectoryInfo dir = new DirectoryInfo(Environment.CurrentDirectory);
          FileInfo[] users = dir.GetFiles("*.usr");      
          foreach(FileInfo user in users)
          {
            ListViewItem item = new ListViewItem(user.Name, 0);
            lstViewUsers.Items.Add(item);
          }
        }
    
        private void btnSelect_Click(object sender, System.EventArgs e)
        {
          if(lstViewUsers.SelectedItems.Count == 0)
            MessageBox.Show("Выберите пользователя для начала работы", "Пользователь не выбран");
          else
          {
            this.DialogResult = DialogResult.OK;
            this.Close();
          }
        }
    
        private void btnCancel_Click(object sender, System.EventArgs e)
        {
          this.Close();
        }
      }
    }

    Форма отправки сообщений SendMessage.cs

    На этой форме подготавливается сообщение к отправке. Значения свойства Name элементов управления приведены на рис. 3.34.

    (рис 3.34) Форма SendMessage

    Полный листинг формы:

    using System;
    using System.Drawing;
    using System.Collections;
    using System.ComponentModel;
    using System.Windows.Forms;
    using System.Web.Mail;
    using System.Threading;
    
    namespace MailApplication
    {
      /// <summary>
      /// Summary description for SendMessage.
      /// </summary>
      public class SendMessage : System.Windows.Forms.Form
      {
        private MailMessage message;
        private System.Windows.Forms.Label lblTo;
        private System.Windows.Forms.TextBox txbTo;
        private System.Windows.Forms.TextBox txbCopy;
        private System.Windows.Forms.Label lblCopy;
        private System.Windows.Forms.TextBox txbBlindCopy;
        private System.Windows.Forms.Label lblBlindCopy;
        private System.Windows.Forms.TextBox txbSubject;
        private System.Windows.Forms.Label lblSubject;
        private System.Windows.Forms.TextBox txbBody;
        private System.Windows.Forms.Label lblBody;
        private System.Windows.Forms.Button btnSend;
        private System.Windows.Forms.Panel pblAttachments;
        private System.Windows.Forms.Label lblAttachments;
        private System.Windows.Forms.Button btnAddAttach;
        private System.Windows.Forms.Button btnViewAttach;
        private System.Windows.Forms.TextBox txbAttach;
        private System.Windows.Forms.Label lblAttachNumber;
        private System.Windows.Forms.OpenFileDialog oFDAttach;
        private System.Windows.Forms.ContextMenu contextMenuDeleteAttach;
        private System.Windows.Forms.MenuItem itemDeleteAttach;
        /// <summary>
        /// Required designer variable.
        /// </summary>
        private System.ComponentModel.Container components = null;
    
        public SendMessage()
        {
          InitializeComponent();
          message = new MailMessage();
        }
    
        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        protected override void Dispose( bool disposing )
        {
          if( disposing )
          {
            if(components != null)
            {
              components.Dispose();
            }
          }
          base.Dispose( disposing );
        }
    
        #region Windows Form Designer generated code
        /// <summary>
        /// Required method for Designer support — do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
          System.Resources.ResourceManager resources = new System.Resources.ResourceManager(typeof(SendMessage));
          this.lblTo = new System.Windows.Forms.Label();
          this.txbTo = new System.Windows.Forms.TextBox();
          this.txbCopy = new System.Windows.Forms.TextBox();
          this.lblCopy = new System.Windows.Forms.Label();
          this.txbBlindCopy = new System.Windows.Forms.TextBox();
          this.lblBlindCopy = new System.Windows.Forms.Label();
          this.txbSubject = new System.Windows.Forms.TextBox();
          this.lblSubject = new System.Windows.Forms.Label();
          this.txbBody = new System.Windows.Forms.TextBox();
          this.lblBody = new System.Windows.Forms.Label();
          this.btnSend = new System.Windows.Forms.Button();
          this.pblAttachments = new System.Windows.Forms.Panel();
          this.lblAttachments = new System.Windows.Forms.Label();
          this.btnAddAttach = new System.Windows.Forms.Button();
          this.btnViewAttach = new System.Windows.Forms.Button();
          this.txbAttach = new System.Windows.Forms.TextBox();
          this.lblAttachNumber = new System.Windows.Forms.Label();
          this.oFDAttach = new System.Windows.Forms.OpenFileDialog();
          this.contextMenuDeleteAttach = new System.Windows.Forms.ContextMenu();
          this.itemDeleteAttach = new System.Windows.Forms.MenuItem();
          this.SuspendLayout();
          // 
          // lblTo
          // 
          this.lblTo.Location = new System.Drawing.Point(32, 16);
          this.lblTo.Name = "lblTo";
          this.lblTo.Size = new System.Drawing.Size(56, 23);
          this.lblTo.TabIndex = 0;
          this.lblTo.Text = "Кому:";
          this.lblTo.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
          // 
          // txbTo
          // 
          this.txbTo.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
            | System.Windows.Forms.AnchorStyles.Right)));
          this.txbTo.Location = new System.Drawing.Point(112, 16);
          this.txbTo.Name = "txbTo";
          this.txbTo.Size = new System.Drawing.Size(560, 20);
          this.txbTo.TabIndex = 1;
          this.txbTo.Text = "";
          // 
          // txbCopy
          // 
          this.txbCopy.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
            | System.Windows.Forms.AnchorStyles.Right)));
          this.txbCopy.Location = new System.Drawing.Point(112, 48);
          this.txbCopy.Name = "txbCopy";
          this.txbCopy.Size = new System.Drawing.Size(560, 20);
          this.txbCopy.TabIndex = 3;
          this.txbCopy.Text = "";
          // 
          // lblCopy
          // 
          this.lblCopy.Location = new System.Drawing.Point(32, 48);
          this.lblCopy.Name = "lblCopy";
          this.lblCopy.Size = new System.Drawing.Size(56, 23);
          this.lblCopy.TabIndex = 2;
          this.lblCopy.Text = "Копия:";
          this.lblCopy.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
          // 
          // txbBlindCopy
          // 
          this.txbBlindCopy.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
            | System.Windows.Forms.AnchorStyles.Right)));
          this.txbBlindCopy.Location = new System.Drawing.Point(112, 80);
          this.txbBlindCopy.Name = "txbBlindCopy";
          this.txbBlindCopy.Size = new System.Drawing.Size(560, 20);
          this.txbBlindCopy.TabIndex = 5;
          this.txbBlindCopy.Text = "";
          // 
          // lblBlindCopy
          // 
          this.lblBlindCopy.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
            | System.Windows.Forms.AnchorStyles.Right)));
          this.lblBlindCopy.Location = new System.Drawing.Point(8, 80);
          this.lblBlindCopy.Name = "lblBlindCopy";
          this.lblBlindCopy.Size = new System.Drawing.Size(88, 23);
          this.lblBlindCopy.TabIndex = 4;
          this.lblBlindCopy.Text = "Скрытая копия:";
          this.lblBlindCopy.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
          // 
          // txbSubject
          // 
          this.txbSubject.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
            | System.Windows.Forms.AnchorStyles.Right)));
          this.txbSubject.Location = new System.Drawing.Point(112, 112);
          this.txbSubject.Name = "txbSubject";
          this.txbSubject.Size = new System.Drawing.Size(560, 20);
          this.txbSubject.TabIndex = 7;
          this.txbSubject.Text = "";
          // 
          // lblSubject
          // 
          this.lblSubject.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
            | System.Windows.Forms.AnchorStyles.Right)));
          this.lblSubject.Location = new System.Drawing.Point(32, 112);
          this.lblSubject.Name = "lblSubject";
          this.lblSubject.Size = new System.Drawing.Size(72, 23);
          this.lblSubject.TabIndex = 6;
          this.lblSubject.Text = "Тема:";
          this.lblSubject.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
          // 
          // txbBody
          // 
          this.txbBody.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
            | System.Windows.Forms.AnchorStyles.Right)));
          this.txbBody.Location = new System.Drawing.Point(16, 168);
          this.txbBody.Multiline = true;
          this.txbBody.Name = "txbBody";
          this.txbBody.Size = new System.Drawing.Size(712, 192);
          this.txbBody.TabIndex = 9;
          this.txbBody.Text = "";
          // 
          // lblBody
          // 
          this.lblBody.Location = new System.Drawing.Point(16, 144);
          this.lblBody.Name = "lblBody";
          this.lblBody.TabIndex = 8;
          this.lblBody.Text = "Текст сообщения:";
          this.lblBody.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
          // 
          // btnSend
          // 
          this.btnSend.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
          this.btnSend.Location = new System.Drawing.Point(648, 440);
          this.btnSend.Name = "btnSend";
          this.btnSend.TabIndex = 10;
          this.btnSend.Text = "Отправить";
          this.btnSend.Click += new System.EventHandler(this.btnSend_Click);
          // 
          // pblAttachments
          // 
          this.pblAttachments.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) 
            | System.Windows.Forms.AnchorStyles.Left) 
            | System.Windows.Forms.AnchorStyles.Right)));
          this.pblAttachments.AutoScroll = true;
          this.pblAttachments.Location = new System.Drawing.Point(16, 416);
          this.pblAttachments.Name = "pblAttachments";
          this.pblAttachments.Size = new System.Drawing.Size(608, 56);
          this.pblAttachments.TabIndex = 12;
          // 
          // lblAttachments
          // 
          this.lblAttachments.Location = new System.Drawing.Point(16, 368);
          this.lblAttachments.Name = "lblAttachments";
          this.lblAttachments.Size = new System.Drawing.Size(64, 23);
          this.lblAttachments.TabIndex = 13;
          this.lblAttachments.Text = "Вложения:";
          this.lblAttachments.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
          // 
          // btnAddAttach
          // 
          this.btnAddAttach.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
          this.btnAddAttach.Location = new System.Drawing.Point(648, 368);
          this.btnAddAttach.Name = "btnAddAttach";
          this.btnAddAttach.TabIndex = 17;
          this.btnAddAttach.Text = "Добавить";
          this.btnAddAttach.Click += new System.EventHandler(this.btnAddAttach_Click);
          // 
          // btnViewAttach
          // 
          this.btnViewAttach.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
          this.btnViewAttach.Location = new System.Drawing.Point(568, 368);
          this.btnViewAttach.Name = "btnViewAttach";
          this.btnViewAttach.TabIndex = 16;
          this.btnViewAttach.Text = "Обзор";
          this.btnViewAttach.Click += new System.EventHandler(this.btnViewAttach_Click);
          // 
          // txbAttach
          // 
          this.txbAttach.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
            | System.Windows.Forms.AnchorStyles.Right)));
          this.txbAttach.Location = new System.Drawing.Point(176, 368);
          this.txbAttach.Name = "txbAttach";
          this.txbAttach.Size = new System.Drawing.Size(384, 20);
          this.txbAttach.TabIndex = 15;
          this.txbAttach.Text = "";
          // 
          // lblAttachNumber
          // 
          this.lblAttachNumber.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
            | System.Windows.Forms.AnchorStyles.Right)));
          this.lblAttachNumber.Location = new System.Drawing.Point(120, 368);
          this.lblAttachNumber.Name = "lblAttachNumber";
          this.lblAttachNumber.Size = new System.Drawing.Size(48, 23);
          this.lblAttachNumber.TabIndex = 14;
          this.lblAttachNumber.Text = "#";
          this.lblAttachNumber.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
          // 
          // oFDAttach
          // 
          this.oFDAttach.Title = "Выбор вложения";
          // 
          // contextMenuDeleteAttach
          // 
          this.contextMenuDeleteAttach.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] {
                                                      this.itemDeleteAttach});
          // 
          // itemDeleteAttach
          // 
          this.itemDeleteAttach.Index = 0;
          this.itemDeleteAttach.Text = "Удалить";
          this.itemDeleteAttach.Click += new System.EventHandler(this.itemDeleteAttach_Click);
          // 
          // SendMessage
          // 
          this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
          this.ClientSize = new System.Drawing.Size(744, 478);
          this.Controls.Add(this.btnAddAttach);
          this.Controls.Add(this.btnViewAttach);
          this.Controls.Add(this.txbAttach);
          this.Controls.Add(this.txbBody);
          this.Controls.Add(this.txbSubject);
          this.Controls.Add(this.txbBlindCopy);
          this.Controls.Add(this.txbCopy);
          this.Controls.Add(this.txbTo);
          this.Controls.Add(this.lblAttachNumber);
          this.Controls.Add(this.lblAttachments);
          this.Controls.Add(this.pblAttachments);
          this.Controls.Add(this.btnSend);
          this.Controls.Add(this.lblBody);
          this.Controls.Add(this.lblSubject);
          this.Controls.Add(this.lblBlindCopy);
          this.Controls.Add(this.lblCopy);
          this.Controls.Add(this.lblTo);
          this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
          this.Name = "SendMessage";
          this.Text = "Отправка сообщения";
          this.WindowState = System.Windows.Forms.FormWindowState.Maximized;
          this.ResumeLayout(false);
    
        }
        #endregion
    
        private void btnViewAttach_Click(object sender, System.EventArgs e)
        {
          if(oFDAttach.ShowDialog() != DialogResult.OK)
            return;
          txbAttach.Text = oFDAttach.FileName;      
        }
    
        private void btnAddAttach_Click(object sender, System.EventArgs e)
        {
          MailAttachment attach = new MailAttachment(oFDAttach.FileName);
          message.Attachments.Add(attach);
          txbAttach.Text = "";
          oFDAttach.FileName = String.Empty;
          this.AddAttachmentsToPanel();
        }
    
        private void AddAttachmentsToPanel()
        {
          pblAttachments.Controls.Clear();
          for(int i = message.Attachments.Count -1; i >= 0; i--)
          {
            MailAttachment attach = (MailAttachment)message.Attachments[i];
            Label lblNumber = new Label();
            Label lblAttachName = new Label();
            lblNumber.Text = String.Format("#{0}", i + 1);
            lblAttachName.Text = attach.Filename;
            lblAttachName.TextAlign = lblNumber.TextAlign = ContentAlignment.MiddleLeft;
            lblAttachName.Anchor = lblNumber.Anchor = AnchorStyles.Top | AnchorStyles.Left;
                    lblNumber.Location = new Point(15, i*25);
            lblAttachName.Location = new Point(50, i*25);
            lblNumber.Size = new Size(20, 20);
            lblAttachName.Size = new Size(500, 20);
            lblNumber.ContextMenu = lblAttachName.ContextMenu = contextMenuDeleteAttach;
            lblNumber.Tag = lblAttachName.Tag = i;
            pblAttachments.Controls.Add(lblNumber);
            pblAttachments.Controls.Add(lblAttachName);
          }
        }
    
        private void itemDeleteAttach_Click(object sender, System.EventArgs e)
        {
          MenuItem item = (MenuItem)sender;
          ContextMenu menu = (ContextMenu)item.Parent;
          Label source = (Label)menu.SourceControl;
          object o = source.Tag;
          int i = Int32.Parse(o.ToString());
          message.Attachments.RemoveAt(i);
          this.AddAttachmentsToPanel();
        }
    
        private void btnSend_Click(object sender, System.EventArgs e)
        {
          message.BodyFormat = MailFormat.Text;
          message.Body = txbBody.Text;
          message.Cc = txbCopy.Text;
          message.Bcc = txbBlindCopy.Text;
          message.Subject = txbSubject.Text;
          message.To = txbTo.Text;
          message.From = ((UserIdentity)Thread.CurrentPrincipal.Identity).Mail;
          Mail.MailSender mailSender = new Mail.MailSender(((UserIdentity)Thread.CurrentPrincipal.Identity).Smtp);
          mailSender.Send(message, ((UserIdentity)Thread.CurrentPrincipal.Identity).Password);
          MessageBox.Show("Ваше сообщение отправлено.");
          this.Close();
        }
      }
    }

    Форма просмотра сообщений ViewMessage.cs

    В эту форму загружается сообщение для чтения при его выборе из списка формы MessageList. Значения свойства Name элементов управления приведены на рис. 3.35.

    (рис 3.35) Форма ViewMessage

    Полный листинг формы:

    using System;
    using System.Drawing;
    using System.Collections;
    using System.ComponentModel;
    using System.Windows.Forms;
    
    namespace MailApplication
    {
      /// <summary>
      /// Summary description for ViewMessage.
      /// </summary>
      public class ViewMessage : System.Windows.Forms.Form
      {
        /// <summary>
        /// Required designer variable.
        /// </summary>    
        private System.ComponentModel.Container components = null;
        
        private System.Windows.Forms.Label lblAttachments;
        private System.Windows.Forms.Panel pblAttachments;
        private System.Windows.Forms.Label lblBody;
        private System.Windows.Forms.Label lblSubject;
        private System.Windows.Forms.Label lblCopy;
        private System.Windows.Forms.Label lblMessageBody;
        private System.Windows.Forms.Label lblFrom;
        private Mail.Message message;
    
        public ViewMessage(Mail.Message msg)
        {
          //
          // Required for Windows Form Designer support
          //
          InitializeComponent();
    
          this.message = msg;
        }
    
        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        protected override void Dispose( bool disposing )
        {
          if( disposing )
          {
            if(components != null)
            {
              components.Dispose();
            }
          }
          base.Dispose( disposing );
        }
    
        #region Windows Form Designer generated code
        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
          System.Resources.ResourceManager resources = new System.Resources.ResourceManager(typeof(ViewMessage));
          this.lblAttachments = new System.Windows.Forms.Label();
          this.pblAttachments = new System.Windows.Forms.Panel();
          this.lblBody = new System.Windows.Forms.Label();
          this.lblSubject = new System.Windows.Forms.Label();
          this.lblCopy = new System.Windows.Forms.Label();
          this.lblFrom = new System.Windows.Forms.Label();
          this.lblMessageBody = new System.Windows.Forms.Label();
          this.SuspendLayout();
          // 
          // lblAttachments
          // 
          this.lblAttachments.Location = new System.Drawing.Point(24, 280);
          this.lblAttachments.Name = "lblAttachments";
          this.lblAttachments.Size = new System.Drawing.Size(64, 23);
          this.lblAttachments.TabIndex = 29;
          this.lblAttachments.Text = "Вложения:";
          this.lblAttachments.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
          // 
          // pblAttachments
          // 
          this.pblAttachments.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) 
            | System.Windows.Forms.AnchorStyles.Left) 
            | System.Windows.Forms.AnchorStyles.Right)));
          this.pblAttachments.AutoScroll = true;
          this.pblAttachments.Location = new System.Drawing.Point(128, 280);
          this.pblAttachments.Name = "pblAttachments";
          this.pblAttachments.Size = new System.Drawing.Size(544, 178);
          this.pblAttachments.TabIndex = 28;
          // 
          // lblBody
          // 
          this.lblBody.Location = new System.Drawing.Point(24, 96);
          this.lblBody.Name = "lblBody";
          this.lblBody.TabIndex = 26;
          this.lblBody.Text = "Текст сообщения:";
          this.lblBody.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
          // 
          // lblSubject
          // 
          this.lblSubject.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
            | System.Windows.Forms.AnchorStyles.Right)));
          this.lblSubject.AutoSize = true;
          this.lblSubject.Location = new System.Drawing.Point(352, 16);
          this.lblSubject.Name = "lblSubject";
          this.lblSubject.Size = new System.Drawing.Size(35, 16);
          this.lblSubject.TabIndex = 24;
          this.lblSubject.Text = "Тема:";
          this.lblSubject.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
          // 
          // lblCopy
          // 
          this.lblCopy.AutoSize = true;
          this.lblCopy.Location = new System.Drawing.Point(24, 56);
          this.lblCopy.Name = "lblCopy";
          this.lblCopy.Size = new System.Drawing.Size(40, 16);
          this.lblCopy.TabIndex = 20;
          this.lblCopy.Text = "Копия:";
          this.lblCopy.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
          // 
          // lblFrom
          // 
          this.lblFrom.AutoSize = true;
          this.lblFrom.Location = new System.Drawing.Point(24, 24);
          this.lblFrom.Name = "lblFrom";
          this.lblFrom.Size = new System.Drawing.Size(47, 16);
          this.lblFrom.TabIndex = 18;
          this.lblFrom.Text = "От кого:";
          this.lblFrom.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
          // 
          // lblMessageBody
          // 
          this.lblMessageBody.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
            | System.Windows.Forms.AnchorStyles.Right)));
          this.lblMessageBody.Location = new System.Drawing.Point(136, 96);
          this.lblMessageBody.Name = "lblMessageBody";
          this.lblMessageBody.Size = new System.Drawing.Size(536, 176);
          this.lblMessageBody.TabIndex = 30;
          // 
          // ViewMessage
          // 
          this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
          this.ClientSize = new System.Drawing.Size(694, 476);
          this.Controls.Add(this.lblMessageBody);
          this.Controls.Add(this.lblAttachments);
          this.Controls.Add(this.pblAttachments);
          this.Controls.Add(this.lblBody);
          this.Controls.Add(this.lblSubject);
          this.Controls.Add(this.lblCopy);
          this.Controls.Add(this.lblFrom);
          this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedToolWindow;
          this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
          this.Name = "ViewMessage";
          this.Text = "Просмотр сообщения";
          this.Load += new System.EventHandler(this.ViewMessage_Load);
          this.ResumeLayout(false);
    
        }
        #endregion
    
        private void ViewMessage_Load(object sender, System.EventArgs e)
        {
          lblMessageBody.Text = this.message.Text;
          lblCopy.Text += this.message.CC;
          lblSubject.Text += this.message.Subject;
          lblFrom.Text += this.message.FromEmail;
        }
    
        private void AddAttachmentsToPanel()
        {
          pblAttachments.Controls.Clear();
          for(int i = message.Attachments.Length -1; i >= 0; i--)
          {
            //MailAttachment attach = (MailAttachment)message.Attachments[i];
            Mail.AttachDescriptor attach = this.message.Attachments[i];
            Label lblNumber = new Label();
            Label lblAttachName = new Label();
            lblNumber.Text = String.Format("#{0}", i + 1);
            lblAttachName.Text = attach.Name;
            lblAttachName.TextAlign = lblNumber.TextAlign = ContentAlignment.MiddleLeft;
            lblAttachName.Anchor = lblNumber.Anchor = AnchorStyles.Top | AnchorStyles.Left;
            lblNumber.Location = new Point(15, i*25);
            lblAttachName.Location = new Point(50, i*25);
            lblNumber.Size = new Size(20, 20);
            lblAttachName.Size = new Size(500, 20);
            //lblNumber.ContextMenu = lblAttachName.ContextMenu = contextMenuDeleteAttach;
            lblNumber.Tag = lblAttachName.Tag = i;
            pblAttachments.Controls.Add(lblNumber);
            pblAttachments.Controls.Add(lblAttachName);
          }
        }
      }
    }
    Страницы:
    Для работы с данной лекцией используйте примеры.

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

    Операция Drag-and-Drop

    Операция Drag-and-Drop предназначена для перемещения и копирования объектов при помощи мыши. Выделив фрагмент текста в Microsoft Word, его можно перетащить в другой документ или в другую позицию текущего документа, нажав и затем отпустив левую кнопку мыши (рис. 3.1).

    (рис 3.1) Перетаскивание выделенного фрагмента текста

    Создайте новое приложение и назовите его DragAndDrop. Расположите на форме два элемента TextBox и один RichTextBox, установив следующие значения свойств:

    textBox1, свойствоЗначение
    Name textBox1
    Location 48; 16
    Size 184; 20
    Text Текст для перетаскивания
    textBox2, свойствоЗначение
    Name textBox2
    AllowDrop True
    Location 48; 64
    Size 184; 20
    Text Сюда можно поместить текст
    richTextBox1, свойствоЗначение
    Name richTextBox1
    AllowDrop True
    Dock Bottom
    Location 0; 130
    Text Текст для Microsoft Word

    Значение True свойства AllowDrop разрешает размещение текстового фрагмента в данном элементе. Выделяем элемент textBox1, в окне Properties переключаемся на его события и дважды щелкаем в поле MouseDown. В обработчике этого события вызываем метод DoDragDrop:

    private void textBox1_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e)
    {
      textBox1.DoDragDrop(textBox1.Text, DragDropEffects.Copy);
    }

    В качестве второго параметра метода мы передаем одно из значений перечисления DragDropEffects — здесь мы выбрали копирование текста Copy. Итак, при нажатой кнопке мыши содержимое текста первого текстового поля будет скопировано. В окне Properties второго элемента TextBox дважды щелкаем в поле события DragEnter. В обработчике этого события будем проверять соответствие представляемых данных формату String:

    private void textBox2_DragEnter(object sender, System.Windows.Forms.DragEventArgs e)
        {
          if (e.Data.GetDataPresent(DataFormats.StringFormat)) 
            e.Effect = DragDropEffects.Copy;
          else
            e.Effect = DragDropEffects.None;
        }

    И наконец, при отпускании кнопки мыши в поле этого же элемента будет выводиться скопированный текст:

    private void textBox2_DragDrop(object sender, System.Windows.Forms.DragEventArgs e)
     {
       textBox2.Text = e.Data.GetData(DataFormats.StringFormat).ToString();
     }

    Для реализации операции Drag-and-Drop в списке событий окна Properties элемента RichTextBox нет нужных нам событий DragDrop и DragEnter, поэтому в области Windows Form Designer generated code нам придется объявить обработчиков для этих событий:

    // 
    // richTextBox1
    //
    …
    this.richTextBox1.DragDrop += new System.Windows.Forms.DragEventHandler
    (this.richTextBox1_DragDrop);
    this.richTextBox1.DragEnter += new System.Windows.Forms.DragEventHandle
    r(this.richTextBox1_DragEnter);

    Делаем проверку на соответствие формату String:

    private void richTextBox1_DragEnter(object sender, 
       System.Windows.Forms.DragEventArgs e)
     {
       if (e.Data.GetDataPresent(DataFormats.Text)) 
         e.Effect = DragDropEffects.Copy;
       else
         e.Effect = DragDropEffects.None;
     }

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

    private void richTextBox1_DragDrop(object sender, 
       System.Windows.Forms.DragEventArgs e)
     {
       int i;
       String s;
    
       // Определяем начальную позицию для текста
       i = richTextBox1.SelectionStart;
       s = richTextBox1.Text.Substring(i);
       richTextBox1.Text = richTextBox1.Text.Substring(0,i);
    
       // Перетаскиваем текст 
       richTextBox1.Text = richTextBox1.Text + 
      e.Data.GetData(DataFormats.Text).ToString();
       richTextBox1.Text = richTextBox1.Text + s;
     }

    Запускаем приложение. Теперь можно перетаскивать текст из верхнего текстового поля в нижнее, а в элемент RichTextBox — даже фрагмент текста из Microsoft Word (рис. 3.2):

    (рис 3.2) Приложение DragAndDrop, перетаскивание фрагмента текста из Microsoft Word

    На диске, прилагаемом к книге, вы найдете приложение DragAndDrop (Code\Glava3\ DragAndDrop).

    Добавление элементов управления в режиме работы приложения. Элементы управления CheckBox, GroupBox и RadioButton

    При размещении на форме элемента управления в режиме дизайна, среда создает код в области Windows Form Designer generated code, описывающий этот элемент. Если мы назначим в обработчике заданного элемента управления генерацию аналогичного кода, то в запущенном приложении можно будет добавлять на форму другие элементы, активизируя этот обработчик. Для добавления элементов управления используется объект ControlsCollection, содержащий ряд методов (см. таблицу 3.1). Под коллекцией элементов понимается их упорядоченная последовательность.

    Некоторые методы ControlsCollection
    МетодОписание
    Add Добавление элемента в коллекцию
    AddRange Добавление массива элементов
    Clear Удаление всех элементов из коллекции
    Remove Удаление элемента из коллекции
    RemoveAt Удаление элемента по заданному индексу
    Count Общее число элементов в коллекции

    Рассмотрим на практике добавление элементов управления. Создайте новое приложение и назовите его RegistrationForm. Располагаем на форме три надписи, два текстовых поля, кнопку, элементы CheckBox и GroupBox (рис. 3.3):

    (рис 3.3) Приложение RegistrationForm. Расположение элементов на форме в режиме дизайна

    Устанавливаем следующие значения свойств формы и элементов управления:

    Form1, форма, свойствоЗначение
    Size 392; 320
    Text Регистрация программы
    label1, свойствоЗначение
    Location 32; 8
    Size 224; 24
    Text Выберите тип регистрации
    label2, свойствоЗначение
    Location 16; 32
    Size 48; 23
    Text Name
    label3, свойствоЗначение
    Location 16; 64
    Size 40; 23
    Text PIN
    Button1, свойствоЗначение
    Location 80; 248
    Size 144; 23
    Text Регистрация
    TextBox1, свойствоЗначение
    Location 96; 32
    Size 184; 20
    Text
    TextBox2, свойствоЗначение
    Location 96; 64
    Size 184; 20
    Text
    CheckBox1, свойствоЗначение
    Location 40; 40
    Size 232; 24
    Text Расширенные возможности
    GroupBox1, свойствоЗначение
    Location 16; 80
    Size 344; 144
    Text Введите регистрационые данные

    Элемент CheckBox обычно применяется для выбора отложенного действия, но в данном случае при его выборе немедленно будет появляться дополнительное текстовое поле и надпись. Щелкаем дважды на этом элементе в режиме дизайна — при этом создается событие CheckedChanged:

    private void checkBox1_CheckedChanged(object sender, System.EventArgs e)
     {
       //Создаем новый экземпляр lbl класса Label:
       Label lbl = new Label();
       //Определяем расположение  надписи — свойство Location
       lbl.Location = new System.Drawing.Point(16, 96);
       //Устанавливаем размер надписи
       lbl.Size = new System.Drawing.Size(32, 23);
       //Задаем имя:
       lbl.Name = "labelll";
       //Определяем порядок переключения при нажатии клавиши Tab
       lbl.TabIndex = 2;
       //Устнаавливаем текст надписи на форме
       lbl.Text = "PIN2";
       //Добавляем элемент в коллекцию, вызывая метод Add
       groupBox1.Controls.Add(lbl);
    
    
       TextBox txt = new TextBox();
       txt.Location = new System.Drawing.Point(96, 96);
       txt.Size = new System.Drawing.Size(184, 20);
       txt.Name = "textboxx";
       txt.TabIndex = 1;
       txt.Text = "";
       groupBox1.Controls.Add(txt);
     
     }

    Запускаем приложение. При выборе пункта "Расширенные возможности" на форме появляется третье текстовое поле. Для определения параметров добавляемого элемента, таких как размер и расположение, лучше всего добавить элемент в режиме дизайна формы, скопировать нужные параметры из области Windows Form Designer generated code, а затем удалить его.

    Добавим на форму два элемента RadioButton (переключателя) — при последовательном их выборе дополнительные текстовое поле и надпись будут появляться или исчезать. Устанавливаем значения свойства Text этим элементам "Полная" и "Ограниченная". Дважды щелкаем на каждый из переключателей, переходя в их код. В обработчике первого элемента RadioButton вставляем скопированный код из обработчика чекбокса. При выборе второго переключателя вся группа элементов, содержащаяся в GroupBox, будет удалена, а затем в новую группу добавятся два текстовых поля и две надписи:

    private void radioButton2_CheckedChanged(object sender, System.EventArgs e)
     {
       //Удаляем все элементы из коллекции
       groupBox1.Controls.Clear();
       
       //Добавляем первую надпись
       Label lbl1 = new Label();
       lbl1.Location = new System.Drawing.Point(16, 32);
       lbl1.Name = "labelfirst";
       lbl1.Size = new System.Drawing.Size(48, 23);
       lbl1.TabIndex = 4;
       lbl1.Text = "Name";
       groupBox1.Controls.Add(lbl1);
       
       //Добавляем вторую надпись
       Label lbl2 = new Label();
       lbl2.Location = new System.Drawing.Point(16, 64);
       lbl2.Name = "labelsecond";
       lbl2.Size = new System.Drawing.Size(40, 23);
       lbl2.TabIndex = 3;
       lbl2.Text = "PIN";
       groupBox1.Controls.Add(lbl2);
    
       //Добавляем первое текстовое поле
       TextBox txt1 = new TextBox();
       txt1.Location = new System.Drawing.Point(96, 32);
       txt1.Name = "textBox1";
       txt1.Size = new System.Drawing.Size(184, 20);
       txt1.TabIndex = 0;
       txt1.Text = "";
       groupBox1.Controls.Add(txt1);
    
       //Добавляем  второе  текстовое поле
       TextBox txt2 = new TextBox();
       txt2.Location = new System.Drawing.Point(96, 64);
       txt2.Name = "textBox2";
       txt2.Size = new System.Drawing.Size(184, 20);
       txt2.TabIndex = 1;
       txt2.Text = "";
       groupBox1.Controls.Add(txt2);
     }

    Запускаем приложение. При выборе переключателя cо значением свойства Text "Полная" снова появляются дополнительные элементы (рис. 3.4):

    (рис 3.4) Результат запуска приложения RegistrationForm

    На диске, прилагаемом к книге, вы найдете приложение RegistrationForm (Code\Glava3\ RegistrationForm).

    Удаление заданного элемента в режиме работы приложения

    В рассмотренном выше примере мы удаляли всю коллекцию элементов. Рассмотрим более сложный пример — удаление добавленного элемента по щелчку правой кнопкой мыши на нем. Создайте новое приложение и назовите его AddRemoveControls. Устанавливаем свойству AutoScroll формы значение True для возможности прокрутки формы. Добавляем на форму кнопку и помещаем ее в верхний левый угол формы. В поле свойства Text кнопки вводим Clone. Переходим в обработчик кнопки:

    private void button1_Click(object sender, System.EventArgs e)
    {
      //Создаем экземпляр btn класса Button
      Button btn = new Button();
      //Определяем количество элементов управления
      Control prev = (Control)this.Controls[this.Controls.Count-1];
      //Устанавливаем позицию добавляемых кнопок
      int x1 = prev.Location.X;
      int y1 = prev.Location.Y;
      int height = prev.Height;
      int width = prev.Width;
      btn.Location = new Point(x1+ width+5, y1 + height +5);
      btn.Width = prev.Width;
      btn.Height = prev.Height;
      //Добавляем событие для новой кнопки и обработчик button1_Click
      btn.Click+= new EventHandler(button1_Click);
      //Устанавливаем свойство Text кнопки
      btn.Text = "Clone";
      //Добавляем экземпляр в коллекцию
      this.Controls.Add(btn);
      //Определяем обработчик для события MouseUp экземпляра кнопки btn
      btn.MouseUp+= new MouseEventHandler(button1_MouseUp);
    }

    Переключаемся в режим дизайна формы, выделяем кнопку, в окне Properties нажимаем на кнопку событий(Events) и дважды щелкаем в поле события MouseUp:

    private void button1_MouseUp(object sender, System.Windows.Forms.MouseEventArgs e)
    {
      if(e.Button==MouseButtons.Right)
      {
     //Удаляем данную кнопку
     this.Controls.Remove((Control)sender);
      }
    }

    Запускаем приложение. При щелчке левой кнопкой мыши на любой из кнопок добавляется еще одна, а при щелчке правой кнопкой мыши на заданной кнопке она исчезает (рис. 3.5):

    (рис 3.5) Результат запуска приложения AddRemoveControls

    На диске, прилагаемом к книге, вы найдете приложение AddRemoveControls (Code\Glava3\ AddRemoveControls).

    Добавление пунктов контекстного меню в режиме запуска приложения. Элемент управления ComboBox

    В зависимости от различных событий, происходящих на форме, содержание контекстного меню может меняться. Создайте новое приложение и назовите его MenuRunTime. Добавляем на форму элемент управления GroupBox (контейнер) и размещаем внутри него две надписи, текстовое поле, кнопку, ComboBox (выпадающий список) (см. рис. 3.6).

    (рис 3.6) Приложение MenuRunTime в режиме дизайна

    Устанавливаем следующие свойства кнопки, текстового поля и выпадающего списка:

    textBox1, свойствоЗначение
    Name txtMenuText
    Text
    comboBox1, свойствоЗначение
    Name cmbShortCuts
    Text
    button1, свойствоЗначение
    Name btnAdd
    Text Добавить

    Добавляем на форму элементы управления ContextMenu и ColorDialog. Свойству СontextMenu формы Form1 устанавливаем значение добавленного контекстного меню — сontextMenu1. Вводим пункты контекстного меню:

    NameTextShortcut
    mnuChangeColor Изменить цвет CtrlG
    mnuExit Выход AltF4

    В обработчике пункта меню mnuChangeColor вызываем диалог colorDialog1 и присваиваем выбранное значение цвета фоновому цвету формы:

    private void mnuChangeColor_Click(object sender, System.EventArgs e)
    {
      if(colorDialog1.ShowDialog()==DialogResult.OK)
      {
     this.BackColor =colorDialog1.Color;
      }
    }

    В обработчике пункта меню "Выход" просто закрываем форму:

    private void mnuExit_Click(object sender, System.EventArgs e)
    {
      this.Close();
    }

    Элемент ComboBox обычно заполняется значениями в режиме дизайна — для этого используется его свойство Items. Однако в нашем примере при загрузке формы мы заполним его всеми значениями сочетаний клавиш, поддерживаемых средой CLR:

    private void Form1_Load(object sender, System.EventArgs e)
    {
      object[] sc = new object[Enum.GetValues(typeof (Shortcut)).Length];
      Enum.GetValues(typeof(Shortcut)).CopyTo(sc,0);
      cmbShortCuts.Items.AddRange(sc);
    }

    В обработчике кнопки btnAdd будет создаваться новый пункт меню и добавляться в контекстное меню сontextMenu1:

    private void btnAdd_Click(object sender, System.EventArgs e)
    {
       //Если значение текстового поля пустое, выводим сообщение
       if(txtMenuText.Text=="")
       {
         //Текст сообщения
         MessageBox.Show("Введите текст для пункта меню");
         return;
       }
        //Если не выбрано значение сочетания клавиш, выводим сообщение
        if(cmbShortCuts.SelectedItem==null)
       {
          //Текст сообщения
         MessageBox.Show("Выберите сочетание клавиш");
         return;
    
       }
       //Создаем новый экземпляр mnu класса пунктов  меню MenuItem
       MenuItem mnu = new MenuItem();
       //Устанавливаем в качестве текста пункта значение, введенное в txtMenuText
       mnu.Text = txtMenuText.Text;
       //Устанавливаем в качестве сочетания клавиш данного пункта 
       //выбранное значение из cmbShortCuts
       mnu.Shortcut=(Shortcut)cmbShortCuts.SelectedItem;
       //Добавляем пункт в контекстное меню contextMenu1
       contextMenu1.MenuItems.Add(mnu);
       //Определяем обработчик для события Click экземпляра  mnu
       mnu.Click += new System.EventHandler(this.NewmnuChangeColor_Click);
        }

    В обработчике нового пункта снова будем вызывать диалог colorDialog1:

    //Обработчик события Click экземпляра mnu
    private void NewmnuChangeColor_Click(object sender, System.EventArgs e)
    {
      if(colorDialog1.ShowDialog()==DialogResult.OK)
      {
     this.BackColor =colorDialog1.Color;
      }
    }

    Запускаем приложение. Цвет формы можно изменить, выбрав соответствующий пункт меню или используя сочетание клавиш Ctrl+G (рис. 3.7). После введения текста пункта, выбора ярлыка и нажатия кнопки "Добавить" новый пункт доступен в меню (рис. 3.8).

    (рис 3.8) Контекстное меню приложения MenuRunTime(рис 3.7) Новый пункт "Снова изменить цвет" в контекстном меню

    Добавление пунктов главного меню в режиме работы приложения ничем не отличается от рассмотренного – если бы мы поместили на форму главное меню, предпоследняя строчка обработчика кнопки btnAdd приняла бы вид:

    //Добавляем пункт в главное меню mainMenu1
    mainMenu1.MenuItems.Add(mnu);

    На диске, прилагаемом к книге, вы найдете приложение MenuRunTime (Code\Glava3\MenuRunTime).

    Проверка вводимых значений. События KeyPress и Validating элемента управления TextBox

    При внесении значений параметров пользователем или заполнении регистрационной формы требуется проверять вводимый текст по заданным критериям. Например, регистрационный номер не должен содержать букв. Рассмотрим проверку, которую можно осуществлять, используя встроенные события текстового поля. Скопируйте папку приложения RegistrationForm и дайте ей новое название — ValidatingInput. Запускаем проект. Текстовым полям, находящимся напротив надписей Name и PIN, задаем названия (значения свойства Name) — txtName и txtPIN соответственно. Располагаем на форме новую надпись lbloutput – на нее будут выводиться сообщения об ошибках, поэтому значение свойства Text оставляем пустым. Выделяем поочередно текстовые поля и в окне Properties создаем обработчиков события KeyPress, возникающего при нажатии любой клавиши в поле. Для элемента txtName недопустимыми значениями будут цифры:

    private void txtName_KeyPress(object sender, System.Windows.Forms.KeyPressEventArgs e)
        {
       if (char.IsDigit(e.KeyChar) )
       {
      e.Handled = true;
         lbloutput.Text = "Поле Name не может содержать цифры";
       }
       
     }

    Для элемента txtPIN, наоборот, недопустимыми значениями будут буквы:

    private void txtPIN_KeyPress(object sender, System.Windows.Forms.KeyPressEventArgs e)
     {
       if (!char.IsDigit(e.KeyChar) )
       {
         e.Handled = true;
         lbloutput.Text ="Поле PIN не может содержать буквы";
       }
    
        }

    Запускаем приложение. При попытке ввести недопустимое значение в одно из полей появляется сообщение, а клавиатура блокируется. Даже стандартная кнопка закрытия формы не работает, пока не будут внесены исправления.

    Для текстового поля, появляющегося при установке галочки в чекбоксе "Расширенные возможности", необходимо вручную определить событие KeyPress:

    private void checkBox1_CheckedChanged(object sender, System.EventArgs e)
    {
      …
      txt.KeyPress+= new System.Windows.Forms.KeyPressEventHandler(this.txtPIN_KeyPress);
    }

    Запускаем приложение. Теперь проверяются значения и в появляющемся поле PIN2 (рис. 3.9).

    (рис 3.9) Проверка значений поля PIN2. Текст сообщения, появляющегося при ошибке, был изменен

    Событие KeyPress блокирует часть клавиатуры. Другим способом проверки является событие Validating, позволяющее работать с клавиатурой, но блокирующее другие действия пользователя. Закомментируем обработчик txtPIN_KeyPress, переключимся в режим дизайна формы и в окне Properties элемента txtPIN создадим обработчик события Validating:

    private void txtPIN_Validating(object sender, System.ComponentModel.CancelEventArgs e)
     {
       if(txtPIN.Text =="")
       {
         e.Cancel=false;
       }
       else
       {
         try
         {
        double.Parse(txtPIN.Text);
        e.Cancel = false;
             
         }
         catch
         {
        e.Cancel = true;
           lbloutput.Text ="Поле PIN не может содержать буквы";
         }
       }
        }

    Для проверки введенное значение преобразуется к типу double — текст сгенерирует исключение. Запускаем приложение. При переключении фокуса ввода или нажатии на кнопку "регистрация" происходит событие Validating.

    На диске, прилагаемом к книге, вы найдете приложение ValidatingInput (Code\Glava3\ ValidatingInput).

    Проверка вводимых значений. Элемент управления ErrorProvider

    Элемент управления ErrorProvider удобно применять, когда нужно выводить небольшую иконку в случае ошибки ввода. Скопируйте папку RegistrationForm и назовите ее ErrorProvider. Запускаем проект, в режиме дизайна из окна ToolBox перетаскиваем на форму элемент управления ErrorProvider. Переходим в код формы. Изменим обработчиков txtName_KeyPress и txtPIN_KeyPress следующим образом:

    private void txtName_KeyPress(object sender, System.Windows.Forms.KeyPressEventArgs e)
     {
       if (char.IsDigit(e.KeyChar) )
       {
         errorProvider1.SetError(txtName, "Must be letter");
         lbloutput.Text = "Поле Name не может содержать цифры";
       }
       
        }
    
     private void txtPIN_KeyPress(object sender, System.Windows.Forms.KeyPressEventArgs e)
     {
       if (!char.IsDigit(e.KeyChar) )
       {
      errorProvider1.SetError(txtPIN, "Must be number");
      lbloutput.Text ="Поля PIN и PIN2 не могут содержать буквы";
       }
    
     }

    Вторым параметром в методе SetError передается строка с описанием ошибки, которая может быть выведена на форму. Мы воспользуемся, однако, выводом сообщения в надписи lbloutput. Запускаем приложение. При ошибке появляется мигающая иконка уведомления (рис. 3.10):

    (рис 3.10) Иконка уведомления элемента ErrorProvider

    Некоторые свойства элемента ErrorProvider, отвечающие за внешний вид иконки, приводятся в таблице 3.2.

    Свойства ErrorProvider
    СвойствоОписаниеЗначение по умолчанию
    Blinkrate Частота мерцания в миллисекундах 250
    BlinkStyle Стиль появления иконки. Возможны следующие варианты: BlinkIfDifferentError – иконка появляется при ошибке, мерцает несколько раз и останавливается;AlwaysBlink – при ошибке иконка мерцает постоянно;NeverBlink – иконка появляется, но не мерцает BlinkIfDifferentError
    Icon Изображение иконки. Можно использовать другие файлы иконок (.ico) (Icon)

    На диске, прилагаемом к книге, вы найдете приложение ErrorProvider (Code\Glava3\ ErrorProvider).

    Создание пользовательских (композитных) элементов управления. Элемент управления NumericUpDown

    Одинаковая группа элементов с привязанными обработчиками может требоваться в нескольких частях большого приложения или даже нескольких приложений. Например, программы Microsoft Word и Excel содержат много одинаковых связанных элементов — панели инструментов, окна настроек, группы меню. Среда Visual Studio .NET предоставляет возможность создания функциональных блоков, состоящих из многих элементов; применение этих блоков позволяет значительно ускорить разработку приложений. Создаем новый проект в Visual Studio .NET — на этот раз выбираем шаблон Windows Control Library (рис. 3.11).

    (рис 3.11) Проект UserInput, шаблон проекта — Windows Control Library

    Появляется форма без границ, представляющая собой основу, на которой будут располагаться элементы. В принципе, можно разрабатывать функциональность и проверять код, компилируя проект при помощи пункта меню Build (Ctrl+Shift+B). Однако при этом мы не увидим результатов работы композитного элемента, пока не добавим его на другую форму. Поэтому на время разработки переделаем проект в Windows-приложение, а потом, когда все будет готово, вернем ему исходный вид. При попытке запустить приложение появляется сообщение "A project with an Output Type of Class Library cannot be started directly" (Проект с выходным типом Class Library (Библиотека классов) не может быть запущен непосредственно). В окне Solution Explorer щелкаем правой кнопкой на имени проекта UserInput и в появившемся контекстном меню выбираем Properties. В окне UserInput Property Pages изменяем значение свойства OutputType на Windows Application. Снова запускаем приложение. Появляется ошибка — приложение не содержит точки входа:

    Program 'D:\Uchebnik\Code\Glava3\UserInput\obj\Debug
    \UserInput.exe' does not have an entry point defined

    Добавляем метод Main в класс формы:

    [STAThread]
     static void Main() 
     {
       Application.Run(new UserControl1());
     }

    Снова запускаем приложение — появляются две ошибки:

    1.D:\Uchebnik\Code\Glava3\UserInput\UserControl1.cs(44): The best overloaded 
    method match for'System.Windows.Forms.Application.Run(System.Windows.Forms.Form)' has
    some invalid arguments
    
    2.D:\Uchebnik\Code\Glava3\UserInput\UserControl1.cs(44): 
    Argument '1': cannot convert from 'UserInput.UserControl1' 
    to 'System.Windows.Forms.Form'

    Класс UserControl1 наследует от класса UserControl:

    public class UserControl1 : System.Windows.Forms.UserControl

    Обычный класс Windows-приложения наследует от класса Form:

    public class Form1 : System.Windows.Forms.Form

    Закомментируем наследование этого класса (не удалим!) и добавим наследование от класса Form:

    public class UserControl1 : System.Windows.Forms.Form

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

    Займемся теперь созданием функциональности. Добавляем на форму три надписи, текстовое поле, ErrorProvider и элемент управления NumericUpDown (рис. 3.12):

    (рис 3.12) Проект UserInput, расположение элементов управления на форме

    Две надписи будут статичными, а на третью будут выводиться сообщения при ошибках. Установим свойству Name этой надписи значение lbloutput. Устанавливаем следующие значения текстового поля, элементов ErrorProvider и NumericUpDown:

    textBox1, свойствоЗначение
    Name txtName
    Text
    numericUpDown1, свойствоЗначение
    Name numUDAge
    Maximum 100
    Minimum 1
    Value 25
    errorProvider1, свойствоЗначение
    BlinkStyle AlwaysBlink
    Icon Code\Glava3\UserInput\Icon\none.ico

    Проверять ввод значений будем в текстовом поле и элементе NumericUpDown. В окне Properties создаем обработчиков событий Validated элементов:

    private void txtName_Validated(object sender, System.EventArgs e)
     {
       if(nameValid())
       {
         // Все правильно, удаляем сообщение с надписи
         errorProvider1.SetError(txtName, "");
       }
       else
       {
         //Поле не заполнено — выводим сообщение
         errorProvider1.SetError(txtName, "Name is required.");
         lbloutput.Text = "Введите имя!";
       }
     
     }
    
     private void numUDAge_Validated(object sender, System.EventArgs e)
     {
       if (ageLess())
       {
      // Введенное значение  меньше 25
         errorProvider1.SetError(numUDAge, "Age not old enough");
         lbloutput.Text = "Введите значение, большее или равное  25";
       }
       else if (ageMore())
       {
         /// Введенное значение  больше 25
         errorProvider1.SetError(numUDAge, "Age is too old");
         lbloutput.Text = "Введите значение, меньшее или равное  65";
       }
       else 
       {
         // Все правильно, удаляем сообщение с надписи
         errorProvider1.SetError(numUDAge, "");
       }
        
     }

    Осталось добавить методы, в которых проверяются заданные значения:

    private bool nameValid() 
     {
       // Проверяем заполнение текствого поля
       return ( txtName.Text.Length > 0);
     }
    
     private bool ageLess() 
     {
     //Возраст меньше 25
       return (numUDAge.Value < 25);
     }
    
     private bool ageMore() 
     {
       //Возраст больше 65
       return (numUDAge.Value > 65 );
     }

    Запускаем приложение. При ошибках иконка мигает беспрерывно, в случае ее исправления сообщение исчезает (рис. 3.13):

    (рис 3.13) Готовое приложение UserInput

    Преобразуем теперь проект в композитный элемент, скомпилируем его в режиме Build (Ctrl+Shift+B) и закроем.

    На диске, прилагаемом к книге, вы найдете приложение UserInput (Code\Glava3\UserInput).

    Добавление пользовательских (композитных) элементов управления

    После создания композитного элемента его можно добавлять в обычные приложения. Создайте новое Windows-приложение и назовите его TestUserElement. В окне Toolbox щелкаем правой кнопкой на закладке Windows Forms и выбираем пункт Add/Remove Items… В окне Customize Toolbox на вкладке .NET Framework Components нажимаем кнопку Browse и выбираем файл UserInput.dll из папки bin/Debug проекта UserInput. В результате в окне компонент появляется элемент UserControl1, принадлежащий пространству имен UserInput (рис. 3.14):

    (рис 3.14) Компонент UserControl1

    Закрываем окно Customize Toolbox — в окне ToolBox создан элемент управления UserControl1, который, как и обычный элемент, мы можем перетаскивать на форму, переименовывать и копировать (рис. 3.15).

    (рис 3.15) Для добавления элемента UserControl1 просто перетаскиваем его на форму

    Для работы композитного элемента уже не требуется никакого кода — он представляет собой полностью автономный функциональный блок (рис. 3.16):

    (рис 3.16) Приложение TestUserElement

    Можно создавать пользовательские элементы управления непосредственно в текущем проекте — для этого в окне Solution Explorer щелкаем на названии проекта TestUserElement и в появившемся меню выбираем Add/Add User Control.

    На диске, прилагаемом к книге, вы найдете приложение TestUserElement (Code\Glava3\TestUserElement).

    Запуск приложения в области уведомлений. Элемент управления NotifyIcon

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

    (рис 3.17) Приложения в области уведомления

    Создайте новое приложение и назовите его SystemTray. Перетаскиваем на форму из окна ToolBox элементы управления ContextMenu и NotifyIcon. Элемент управления NotifyIcon и представляет собой отображение запущенного приложения в области задач. Добавляем пункты контекстного меню и устанавливаем следующие свойства элемента NotifyIcon:

    contextMenu1,
    свойство Name Text
    mnuShow Показать
    mnuHide Скрыть
    notifyIcon1, свойствоЗначение
    СontextMenu contextMenu1
    Icon Code\Glava3\SystemTray\Icon\ eventlogWarn.ico
    Text Область уведомлений

    Изображение, используемое в качестве иконки (свойство Icon) элемента NotifyIcon, будет выводиться в область уведомлений. Значение свойства Text представляет собой текст всплывающей подсказки, появляющейся при наведении курсора на иконку приложения. Добавляем обработчик пункта меню mnuShow:

    private void mnuShow_Click(object sender, System.EventArgs e)
     {
       //Включаем отображения приложения на панели задач при запуске
       this.ShowInTaskbar = true;
       //Показываем форму
       this.Show();
       //Отключаем доступность пункта меню mnuShow
       mnuShow.Enabled = false;
       //Включаем доступность пункта меню mnuHide
       mnuHide.Enabled = true;
       //Переменной Hidden устанавливаем значение false
       
     }

    Обработчик пункта меню mnuHide изменяет эти значения на обратные:

    private void mnuHide_Click(object sender, System.EventArgs e)
     {
       this.ShowInTaskbar = false;
       this.Hide();
       mnuShow.Enabled = true;
       mnuHide.Enabled = false;
       
     }

    В конструкторе формы скрываем видимость приложения на панели задач при запуске:

    public Form1()
     {
       InitializeComponent();
       this.ShowInTaskbar = false;
     }

    Переключаемся в режим дизайна, в окне Properties элемента управления NotifyIcon переключаемся на события и дважды щелкаем в поле события DoubleClick:

    private void notifyIcon1_DoubleClick(object sender, System.EventArgs e)
    {
      mnuShow_Click(this, new EventArgs());
    }

    В результате обработчиком события notifyIcon1_DoubleClick будет обработчик mnuShow_Click. Запускаем приложение. При сворачивании приложение исчезает с панели задач, а развернуть его можно, щелкнув дважды на иконке в области уведомлений или выбрав пункт "Показать в контекстном меню" (рис. 3.18 и рис. 3.19):

    (рис 3.19) При наведении курсора на иконку появляется подсказка — "Область уведомлений"(рис 3.18) Контекстное меню

    На диске, прилагаемом к книге, вы найдете приложение SystemTray (Code\Glava3\SystemTray).

    Сохранение настроек приложения. 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>
    (рис 3.20) Файл applicationSettings.xml в окне Solution Explorer

    Добавим теперь обработчик для события 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.

    Основные разделы реестра операционной системы Windows
    РазделыОписание
    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одержится информация о конфигурации устройств PlugPlay и сведения о конфигурации компьютера с переменным составом аппаратных средств
    HKEY_DYN_DATA Содержатся динамические данные о состоянии различных устройств, установленных на компьютере пользователя

    Конечным элементом дерева реестра являются ключи или параметры, среди которых можно выделить три основных типа:

  • строковые (например, "C:\Program Files");
  • двоичные (например. 06 31 B2 8C). Максимальная длина такого ключа 16Кб;
  • тип DWORD. Этот тип ключа занимает 4 байта и отображается в шестнадцатеричном и в десятичном виде (например, 0x00000001 (1) — в скобках указано десятичное значение ключа).
  • Основным классом для работы с реестром (создание новых ключей, их удаление и изменение) в библиотеке .NET Framework является RegistryKey. Описание некоторых методов этого класса приводится в таблице 3.4.

    Некоторые методы класса RegistryKey
    МетодОписание
    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):

    (рис 3.21) Раздел RegApplication с двоичными ключами Height и Width

    На диске, прилагаемом к книге, вы найдете приложение RegistrySettings (Code\Glava3\ RegistrySettings).

    Почтовая программа Ballet

    До сих пор мы рассматривали небольшие программки, которые создавали сами. Теперь мы приступим к рассмотрению блоков достаточно большой программы – почтового клиента Ballet. Исходный код содержит подробные комментарии, и вы можете воспроизвести весь проект заново. Он находится на диске, прилагаемом к книге (Code\Glava3\Mail). Возможно, некоторые вопросы покажутся вам незнакомыми; после прочтения всей книги вы сможете вернуться к ним заново — тогда многое станет понятным. Подобно большинству почтовых клиентов, программа Ballet позволяет отправлять, получать, управлять почтовыми сообщениями и вложениями (рис. 3.22 и рис. 3.23). Поддерживается работа нескольких независимых пользователей и почтовых ящиков.

    (рис 3.23) Написание письма в программе Ballet(рис 3.22) Форма для получения списка в почтовом ящике

    Рассмотрим несколько деталей программы, интересных с технической точки зрения, а потом приступим к разработке программы.

    Добавление проектов

    При создании большой программы лучше всего работать над ее частями отдельно, помещая их в проекты. В папке Mail (Code\Glava3\Mail) содержатся три проекта в папках Mail 2003, SendMail и MailApplication. В папке Mail2003 содержится код для приема почтовых сообщений, в папке SendMail — код для его отправки, а в папке MailApplication находится интерфейс программы и добавлены проекты Mail из папки Mail 2003 и SendMail из одноименной папки. В терминах Visual Studio .NET любой создаваемый проект представляет собой часть разработки (решения) Solution (рис. 3.22).

    (рис 3.22) Разработка (решение) Solution в окне Solution Explorer

    При открывании ранее сохраненного проекта мы открывали именно файл NameApplication.sln, представляющий собой решение. Для добавления проектов в решение щелкаем правой кнопкой на его названии и в появившемся меню выбираем Add/New Project (новый проект) или Existing Project (существующий проект) в зависимости от того, что нам нужно (рис. 3.23):

    (рис 3.23) Добавление проектов Mail и SendMail в разработку MailApplication

    Обратите внимание на то, что само решение MailApplication содержит проект MailApplication. Проекты, объединенные в рамках одного решения, являются связанными, а не внедренными. В этом нетрудно убедиться, переименовав папку одного из проектов или внеся изменения в код: в первом случае в результирующем решении будет ошибка, во втором – изменения затронут листинги и в решении.

    Создание Мастера

    Во многих программах, когда требуется получить последовательный ряд каких-либо значений, диалоговые окна представляют в виде МастераТочный перевод c англ. слова Wizard – "волшебник", но, следуя устоявшейся традиции, я буду использовать далее слово "Мастер". (Wizard). В программе Ballet с помощью Мастера пользователь вводит необходимые параметры, причем они также проходят проверку (рис. 3.24).

    (рис 3.24) Мастер регистрации пользователя

    Форма Мастера появляется при выборе пункта главного меню "Новый пользователь" : Здесь и далее приводятся только те фрагменты кода, о которых идет речь в текущем разделе.

    private void itemNewUser_Click(object sender, System.EventArgs e)
      {
     //Создаем экземпляр wizard формы CreateUserWizard
     CreateUserWizard wizard = new CreateUserWizard();
     //Показываем форму:
     wizard.ShowDialog();
     …
      }

    Форма CreateUserWizard (рис. 3.25) представляет собой контейнер для форм CUWStep1, CUWStep2, CUWStep3.

    (рис 3.25) Родительская форма CreateUserWizard и дочерние формы CUWStep1, CUWStep2, CUWStep3 в режиме дизайна

    Обратите внимание на заголовок запущенной формы CreateUserWizard — к нему добавляются названия дочерних форм. После запуска формы CreateUserWizard в нее загружается форма CUWStep1:

    private void CreateUserWizard_Load(object sender, System.EventArgs e)
      {
     …  
     CUWStep1 step1 = new CUWStep1(identity);
     step1.MdiParent = this;
     step1.Show();
      }

    В обработчике кнопки "Далее" проверяется значение, введенное в текстовое поле, затем закрывается текущая форма и вызывается форма CUWStep2:

    private void btnNext_Click(object sender, System.EventArgs e)
      {
     if(txbEmail.Text == "")
     {
       MessageBox.Show("Введите адрес электронной почты.");
       return;
     }
     else
     {
       …
       CUWStep2 step2 = new CUWStep2(this.identity);
       step2.MdiParent = this.MdiParent;
       this.Close();
       step2.Show();
     }
      }

    В обработчике кнопки "Далее" формы CUWStep2 для проверки введенного значения снова применяется преобразование типов данных:

    private void btnNext_Click(object sender, System.EventArgs e)
    {
     if(txbPop3.Text == "")
     {
       MessageBox.Show("Введите адрес сервера POP3");
     }
     else
     {
       this.identity.Pop3 = txbPop3.Text;
       try
       {
      //Преобразовываем введенное значение в тип Int32 
      this.identity.Pop3Port = Int32.Parse(txbPop3Port.Text);
      CUWStep3 step3 = new CUWStep3(this.identity);
      step3.MdiParent = this.MdiParent;
      this.Close();
      step3.Show();
       }
       catch(Exception)
       {
      MessageBox.Show("Значение порта должно быть числом");
       }
     }
      }

    В последнем шаге Мастера необходимо закрыть не только форму CUWStep3, но также родительскую форму CreateUserWizard, которая, в свою очередь, является дочерней по отношению к главной форме mainForm. Родительская форма CreateUserWizard будет активной в этот момент, поэтому метод ActiveForm.Close() закроет ее:

    private void btnFinish_Click(object sender, System.EventArgs e)
      {
     if(txbSmtp.Text != "")
     {
       this.identity.Smtp = txbSmtp.Text;
       //Закрываем текущую форму
       this.Close();
       Thread.CurrentPrincipal = new GenericPrincipal
    (this.identity, new string[]{"user"});
       this.identity.Dispose();
       //Закрываем родительскую форму CreateUserWizard  
       Form.ActiveForm.Close();
       
     }
     else
     {
       MessageBox.Show("Введите адрес сервера SMTP");
     }
      }

    Итак, при запуске Мастера применяется форма, в которую последовательно загружаются дочерние формы. После выполнения всех действий в коде дочерней формы закрывается главная.

    Запуск формы-заставки при загрузке приложения

    При запуске программы Ballet появляется список пользователей, из которого требуется выбрать заданного для начала работы с программой (рис. 3.26).

    (рис 3.26) Форма выбора пользователя программы Ballet

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

    this.Load += new System.EventHandler(this.itemUsers_Click);

    Этот же обработчик привязан к пункту меню "Смена пользователя" в главном меню, он и вызывает форму выбора пользователя:

    private void itemUsers_Click(object sender, System.EventArgs e)
      {
     selectUser select = new selectUser();
     if(select.ShowDialog() != DialogResult.OK)
     //Запускаем главную форму.
       return;
    …
     //Вызываем метод ActivateEventItem
     this.ActivateEventItem();
      }

    В обработчике кнопки "Выбор" проверяется, выбран ли хотя бы один пользователь из списка:

    private void btnSelect_Click(object sender, System.EventArgs e)
      {
      if(lstViewUsers.SelectedItems.Count == 0)
      MessageBox.Show("Выберите пользователя для начала работы",
     "Пользователь не выбран");
      else
      {
     this.DialogResult = DialogResult.OK;
     this.Close();
      }
      }

    После выбора появляется главная форма — это указывается в обработчике itemUsers_Click. Если миновать выбор пользователя, главная форма запускается с недоступным пунктом меню "Действия". После выбора пользователя вызывается метод ActivateEventItem, в котором включается пункт меню:

    private void ActivateEventItem()
      {
     //Включаем доступность пункта меню "Действия".
     this.itemEvent.Enabled = true;
      }

    Получение сообщений – проект Mail

    Классы для обработки исключений Exceptions

    Класс CoreException.cs

    using System;
    
    namespace Mail
    {
      /// <summary>
      /// Класс для обработки  основных исключений.
      /// </summary>
      public class CoreException : ApplicationException
      {
     /// <summary>
     /// Инициализация исключения без дополнительных параметров.
     /// </summary>
     public CoreException() : base() 
     {
     }
    
     /// <summary>
            /// Инициализация исключения с дополнительным описанием.
     /// </summary>
     public CoreException(string message) : base(message) 
     {
     }
    
     /// <summary>
            /// Инициализация исключения с дополнительным описанием и внутренним исключением  
     /// </summary>
     public CoreException(string message, System.Exception inner) : base(message, inner) 
     {
     }   
      }
    }

    Класс DeadConnectionException.cs

    using System;
    
    namespace Mail
    {
      /// <summary>
        /// Класс для обработки исключений установки связи.
      /// </summary>
      public class DeadConnectException : CoreException
      {
     /// <summary>
            /// Инициализация исключения без дополнительных параметров.
     /// </summary>
     public DeadConnectException() : base() 
     {
     }
    
     /// <summary>
            /// Инициализация исключения с дополнительным описанием.
     /// </summary>
     public DeadConnectException(string message) : base(message) 
     {
     }
    
     /// <summary>
            /// Инициализация исключения с дополнительным описанием и внутренним исключением.
     /// </summary>
     public DeadConnectException(string message, System.Exception inner) : base(message, inner) 
     {
     }   
      }
    }

    Класс ParseException.cs

    using System;
    
    namespace Mail
    {
      /// <summary>
        /// Класс для обработки исключений, возникающих  в момент анализа ответа.
      /// <summary>
      public class ParseException: CoreException
      {
     public ParseException(string message) : base(message) 
     {
     }
    
     public ParseException(string message, System.Exception inner) : 
     base(message, inner) 
     {
     }   
      }
    }

    Класс ResponseException.cs

    using System;
    
    namespace Mail
    {
      /// <summary>
        /// Класс для обработки исключений POP3Unit
      /// </summary>
      public class ResponseException : CoreException
      {
     public ResponseException(string message) : base(message) 
     {
     }
    
     public ResponseException(string message, System.Exception inner) : 
     base(message, inner) 
     {
     }   
      }
    }

    Класс ShutdownException.cs

    using System;
    
    namespace Mail
    {
      /// <summary>
        /// Класс для обработки исключений POP3Unit
      /// </summary>
      public class ShutdownException: CoreException
      {
     public ShutdownException(string message) : 
     base(message) 
     {
     }
    
     public ShutdownException(string message, System.Exception inner) : 
     base(message, inner) 
     {
     }   
      }
    }

    Библиотека конвертирования Library

    Класс FromQuotedPrintableTransform.cs

    using System;
    using System.Security.Cryptography;
    using System.Text;
    
    namespace Mail
    {
      /// <summary>
      /// Конвертирование  CryptoStream.
      /// <summary>
      public class FromQuotedPrintableTransform : ICryptoTransform, IDisposable
      {
     // максимальный размер входного\выходного блока.
     const int MAX_BUF = 3;
    
     // буфер
     byte [] _buf = null;
    
     /// <summary>
            /// Значение, указывающее на возможность повторного использования текущей трансформации
     /// </summary>
     public bool CanReuseTransform
     {
       get
       {
      return true;
       }
     }
    
     /// <summary>
            /// Значение, указывающее на возможность трансформации  составных блоков.
     /// </summary>
     public bool CanTransformMultipleBlocks
     {
       get
       {
      return false;
       }
     }
    
     /// <summary>
     /// Возвращение выходного размера блока.
     /// </summary>
     public int OutputBlockSize
     {
       get
       {
      return MAX_BUF;
       }
     }
    
     /// <summary>
     /// Возвращение входного  размера  блока.
     /// </summary>
     public int InputBlockSize
     {
       get
       {
      return MAX_BUF;
       }
     }
    
     /// <summary>
     /// Удаление  всех элементов.
     /// </summary>
     public void Dispose()
     {
       _buf = null;
       GC.SuppressFinalize(this);
     }
    
    
     /// <summary>
     /// Конвертирование  указанного  участка  входящего массива байтов из quoted-printable (RFC 2045 (6.7)) 
     /// и копирование результата  в указанный участок выходного массива байтов. 
     /// </summary>
     /// <param name="inputBuffer">Входящий массив байтов.</param>
     /// <param name="inputOffset">Начальная отметка участка, который нужно конвертировать.</param>
     /// <param name="inputCount">Количество байтов после индекса начала участка.</param>
     /// <param name="outputBuffer">Выходной массив байтов, в который требуется записать результат.</param>
     /// <param name="outputOffset">Начальная отметка участка, после которого необходимо вписать результат.</param>
     /// <returns>Количество вписанных байтов.</returns>
     public int TransformBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset)
     {
       // append unparsed characters
       if (_buf != null)
       {
      byte [] tmp = new byte[inputCount + _buf.Length];
      Array.Copy(_buf, 0, tmp, 0, _buf.Length);
      Array.Copy(inputBuffer, inputOffset, tmp, _buf.Length, inputCount);
      inputBuffer = tmp;
    
      inputCount = tmp.Length;
      _buf = null;
          } 
          else 
          {
            byte [] tmp = new byte[inputCount];
            Array.Copy(inputBuffer, inputOffset, tmp, 0, inputCount);
            inputBuffer = tmp;
          }
    
          int c = 0;
          int obi = outputOffset;
    
          while (c < inputCount)
          {
            byte cb = inputBuffer[c++];
            // skip CRLFs
            if (cb == '=') 
            {
              // impossible to get next 2 bytes, save unparsed characters 
              // for next session
              if (c + 1 >= inputCount) 
              {
                int len = inputCount - c;
                _buf = new byte[len + 1]; // +1 is for '='
                Array.Copy(inputBuffer, c - 1, _buf, 0, len + 1);
                break;
              } 
                        
              // skip =\r\n
              if (!(inputBuffer[c] == '\r'  inputBuffer[c + 1] == '\n'))
              {
                // TODO Add check. Uppercase letters must be used (=DD);  
                // lowercase letters are not allowed. 
                try
                {
                  byte b = Convert.ToByte(Encoding.ASCII.GetString(inputBuffer, c, 2), 16);
                  outputBuffer[obi++] = b;
                } 
                catch (FormatException e)
                {
                  throw new ParseException("Incorrect sequence. Are you sure that it's quoted-printable?", e);
                }
              }
    
              // take next sequence
              c += 2; 
            } 
            // incorrect characters for quoted-printable, just skip it
            else if (!(cb == '\r' || cb == '\n')) 
            {          
              outputBuffer[obi++] = cb;
            }
          }
    
          return obi - outputOffset;
        }
    
        /// <summary>
        /// Конвертирование  указанного участка  входящего массива байтов из quoted-printable (RFC 2045 (6.7)).
        /// </summary>
        /// <param name="inputBuffer">Входящий массив байтов.</param>
        /// <param name="inputOffset">Начальная отметка участка, который нужно конвертировать.</param>
        /// <param name="inputCount">Количество байтов  после индекса начала участка.</param>
        /// <returns>Полученный массив байтов.</returns>
        public byte[] TransformFinalBlock(byte[] inputBuffer, int inputOffset, int inputCount)
        {
          byte [] b = new byte[inputCount];
          int s = TransformBlock(inputBuffer, inputOffset, inputCount, b, 0);
    
          byte [] c = new byte[s];
          Array.Copy(b, 0, c, 0, s);
          return c;
        }
      }
    }

    Класс Utils.cs

    using System;
    using System.Text.RegularExpressions;
    using System.Collections;
    using System.Text;
    using System.Web;
    
    namespace Mail
    {
      /// <summary>
      /// Класс, содержащий общие функции.
      /// </summary>
      public class Utils
      {
        // Архив кодировок.
        static Hashtable knownEncodings = new Hashtable();
    
        static Utils()
        {
    
        }
        /// <summary>
        /// Извлечение  простого текста из HTML-текста.
        /// </summary>
        /// <param name="html">HTML текст.</param>
        /// <returns>Простой текст.</returns>
        public static string ExtractTextFromHtml(string html)
        {
          // С помощью регулярных выражений удаляем или заменяем
          // HTML-теги.
          // удаление  <!DOCTYPE ... >
          Regex r = new Regex(@"<![^>]+>"); // Создание регулярного выражения.
          html = r.Replace(html, ""); // Замена подходящей части текста на пустую строку.
    
          // удаление <head>...</head>
          r = new Regex(@"<head>.*?</head>", RegexOptions.IgnoreCase); // Создание регулярного выражения.
          // r = new Regex(@"<style[^>]+[>].*?</style>", RegexOptions.IgnoreCase);
          html = r.Replace(html, ""); // Замена подходящей части текста на пустую строку.
          // представляем, что </div>, <br />, </p> — это новая строка
          r = new Regex(@"(</div>|<[/]?br[^>]+>|</p>)", RegexOptions.IgnoreCase); // Создание регулярного выражения.
          html = r.Replace(html, "\r\n"); // Замена подходящей части текста на символы перехода на новую строку.
    
          // удаление всех тегов <...>
          r = new Regex(@"<[^>]+>", RegexOptions.Multiline); // Создание регулярного выражения, удаляющего все оставшиеся теги.
          html = r.Replace(html, ""); 
                html = HttpUtility.HtmlDecode(html);
          return html;
        }
    
        /// <summary>
        /// Возвращение  кодировки текста.
        /// </summary>
        /// <param name="charset">Текст, содержащий название кодировки.</param>
        /// <returns></returns>
        public static Encoding GetEncoding(string charset)
        {
          // Проверяем, есть ли данная кодировка в памяти класса,
          // и если есть, возвращаем ее.
          if (knownEncodings.ContainsKey(charset)) 
          {
            return (Encoding)knownEncodings[charset];
          }
          // Если кодировка не обнаружена,  начинаем анализировать строку.
          Encoding e = Encoding.Default;
          try
          {
            e = Encoding.GetEncoding(charset);
          }
          catch {}
    
          // Добавляем кодировку в память класса.
          knownEncodings.Add(charset, e);
          // Возвращаем кодировку.
          return e;
        }
    
    
        /// <summary>
        /// Исключаем "byte-stuffed", следуя RFC1939 
        /// \r\n.[not \r\n] => \r\n[not \r\n]
        /// </summary>
        /// <param name="s"></param>
        /// <returns></returns>
        public static string RemoveByteStuffedSequence(string s)
        {
          Regex r = new Regex(@"(?<=\r\n)\.(?!\r\n)");
          return r.Replace(s, "");
        }
    
        /// <summary>
            /// Декодируем строку
        /// </summary>
        /// <param name="s">Строка</param>
        /// <returns></returns>
        public static string DecodeQuotedPrintable(string s, Encoding e)
        {
          _curEncoding = e;
          Regex re = new Regex(@"=([a-fA-F0-9]{2})");
          return re.Replace(s, new MatchEvaluator(ReDigit));
        }
    
    
        static Encoding _curEncoding;
        /// <summary>
            /// Конвертирует "ХХ" в байтовый аналог
        /// </summary>
        /// <param name="match">"XX" формат</param>
        /// <returns></returns>
        static string ReDigit(Match match)
        {
          byte [] tmp = {Convert.ToByte(match.Groups[1].Value, 16)};
          return "" + _curEncoding.GetString(tmp);
        }
    
        /// <summary>
        /// RFC 2047
        /// </summary>
        /// <param name="s"<</param>
        /// <returns<</returns>
        public static string WordDecoder(string input)
        {
          string charset = "";
          string src;
          string tmp;
          src = input;
          Match m = Regex.Match(input, @"(?<ew>(?<n>\=\?(?<charset>[^?]+)\?(?<encoding>[QqBb])\?(?<content>[^?]+)\?\=)(\r\n)*\s*)(?=(?<isnext>\=\?[^?]+\?[QqBb]\?[^?]+\?\=)*)", RegexOptions.Multiline);
          if (m.Success)
          {
            while (m.Success)
            {
              charset = m.Groups["charset"].Value;
              string encoding = m.Groups["encoding"].Value.ToLower();
              switch(encoding)
              {
                case "q":
                  tmp = m.Groups["content"].Value.Replace("_", " ");
                  tmp = DecodeQuotedPrintable(tmp, GetEncoding(m.Groups["charset"].Value));
                  break;
    
                case "b":
                  tmp = GetEncoding(charset).GetString(Convert.FromBase64String(m.Groups["content"].Value));
                  break;
    
                default:
                  throw new ParseException("Неизвестный метод кодировки");
              }
    
              src = src.Replace(((m.Groups["isnext"].Value.Length == 0) ? m.Groups["n"].Value : m.Groups["ew"].Value), tmp);
              m = m.NextMatch();
            }
    
            return src; 
          }
    
          return GetEncoding(charset).GetString(Encoding.Default.GetBytes(src));
        }
      }
    }

    Формирование сообщений

    Класс MessageFile.cs

    namespace Mail.Providers
    {
      using System;
      using System.IO;
      using System.Diagnostics;
      using System.Text;
    
      /// <summary>
      /// Провайдер для .eml-файлов.
      /// </summary>
      public class MessageFile : Provider
      {
        const string FiveOctalTerm = "\r\n.\r\n";
    
        FileStream fs = null;
    
        /// <summary>
        /// Конструктор.
        /// </summary>
        /// <param name="filename">Адрес к файлу.</param>
        public MessageFile(string filename)
        {
                fs = new FileStream(filename, FileMode.Open, FileAccess.Read);
          TempDirectory = Path.GetTempPath();
        }
    
        /// <summary>
            /// Не реализовано
        /// </summary>
        /// <param name="i"></param>
        public override void DeleteMessage(uint index)
        {
                Debug.WriteLine("Не реализовано");
        }
    
        string TruncateTail(string message)
        {
          if (!message.EndsWith(FiveOctalTerm))
          {
                    Debug.WriteLine("Последние 5 символов: {" + message.Substring(message.Length - 5) + "}");
                    throw new ResponseException("Неправильные символы конца сообщения.");
          }
    
          return message.Remove(message.Length — FiveOctalTerm.Length, FiveOctalTerm.Length);
        }
    
        /// <summary>
        /// Не реализовано.
        /// </summary>
        /// <param name="i"></param>
        public override Message GetMessage(uint index)
        {
          byte [] buf = new byte[fs.Length];
          fs.Read(buf, 0, buf.Length);
          fs.Position = 0;
    
          string message = Utils.RemoveByteStuffedSequence(Encoding.ASCII.GetString(buf));
          return new Message(this, message, index);
        }
    
        /// <summary>
        /// Этот метод необязателен.
        /// </summary>
        /// <param name="name"></param>
        /// <param name="pass"></param>
        public override void LogIn(string name, string pass)
        {
                Debug.WriteLine("Не реализовано");
        }
    
        /// <summary>
        /// Закрытие потока.
        /// </summary>
        public override void Dispose()
        {
          try
          {
            Quit();
          } 
          catch
          {
          }
    
                GC.SuppressFinalize(this);      
        }
    
        /// <summary>
        /// Закрытие FilеStream.
        /// </summary>
        public override void Quit()
        {
                fs.Close();
        }
      }
    }

    Класс MaildropStatus.cs

    using System.Collections;
    
    namespace Mail.Providers
    {
      /// <summary>
      /// Содержание информации о почтовом ящике  (размер и количество сообщений).
      /// </summary>
      class MaildropStatus
      {
        internal uint messages;
        internal uint size;
    //    internal Hashtable messagelist;
    
        /// <summary>
            /// Конструктор с параметрами: количество сообщений и размер.
        /// </summary>
            /// <param name="messages">Количество сообщений.</param>
        /// <param name="size">Размер сообщений.</param>
        public MaildropStatus(uint messages, uint size)
        {
          this.messages = messages;
          this.size = size;
        }
      }
    }

    Класс Pop3.csM

    //#define _DEBUG
    
    using System;
    using System.IO;
    using System.Net;
    using System.Net.Sockets;
    using System.Diagnostics;
    using System.Collections;
    using System.Text;
    using System.Text.RegularExpressions;
    
    namespace Mail.Providers
    {
      /// <summary>
      /// Реализация протокола POP3
      /// </summary>  
      /// <example>Пример получения сообщения.
      /// <code>
      /// using (Pop3 pop3 = new Pop3("host"))
      ///  {
      ///    pop3.LogIn("Username", "Password");
      ///    Console.WriteLine("Количество сообщений:" + pop3.NumberOfMessages);
      ///    
      ///    using(Message msg = pop3.GetMessage(1)) // получение первого сообщения
      ///    {
      ///      Console.WriteLine("Тема: " + msg.Subject); 
      ///    }
      ///  }
      /// </code>
      /// </example>  
      public class Pop3 : Provider
      {
        #region Constants
        const int MaxReceiveSize = 1024;
        const int POP3DefaultPort = 110;
    
        const int SendTimeout = 60000; // в милисекундах.
            public int ReceiveTimeout = 2000000; // в милисекундах.
            public int PollTimeout = 100000; // в микросекундах.
    
        const string CRLF = "\r\n";
        
        const string FiveOctalTerm = "\r\n.\r\n";
        const string STAT_OK = "+OK";
        const string STAT_ERR = "-ERR";
    
        const char SPACE = ' ';
        const char CR = '\r';
        #endregion
    
        Socket _socket = null;
    
            MaildropStatus _status = null;
        uint [] _messagelist = null;
    
        bool _authenticated = false;
    
        #region DEBUG functions
        FileStream GetDebugStream()
        {
          return new FileStream(@"C:\trace_response.log", FileMode.Append);
        }
        [Conditional("_DEBUG")]
        void Trace(byte [] str)
        {
          FileStream fs = GetDebugStream();
          fs.Write(str, 0, str.Length);
          fs.Close();
        }
    
        [Conditional("_DEBUG")]
        void Trace(string str)
        {
          FileStream fs = GetDebugStream();
          fs.Write(Encoding.ASCII.GetBytes(str), 0, str.Length);
          fs.Close();
        }
        #endregion
    
        #region Constructors 
        /// <summary>
            /// Инициализация класса установленным по умолчанию портом (110) и установка  адреса временной папки 
            /// на текущую системную временную папку.    
        /// </summary>
        /// <param name="server">IP адрес сервера.</param>
        public Pop3(string server)
        {
          _server = server;
          _port = POP3DefaultPort;
          TempDirectory = Path.GetTempPath();
        }
    
        /// <summary>
            /// Инициализация класса а установленным по умолчанию портом (110).
        /// </summary>
            /// <param name="server">IP адрес сервера.</param>
        /// <param name="temp">Адрес временной папки.</param>
        public Pop3(string server, string temp)
        {
          _server = server;
          _port = POP3DefaultPort;
          TempDirectory = temp;
        }
    
        /// <summary>
        /// Инициализация класса .
        /// </summary>
            /// <param name="server">IP адрес сервера.</param>
        /// <param name="port">Номер порта.</param>
        public Pop3(string server, int port)
        {
          _server = server;
          _port = port;
          TempDirectory = Path.GetTempPath();
        }
    
        /// <summary>
            /// Инициализация класса .
        /// </summary>
            /// <param name="server">IP-адрес сервера.</param>
            /// <param name="port">Номер порта.</param>
            /// <param name="temp">Адрес временной папки.</param>
        public Pop3(string server, int port, string temp)
        {
          _server = server;
          _port = port;
          TempDirectory = temp;
        }
        #endregion
    
        #region Public properties
        /// <summary>
        /// Возвращается значение  true, если в почтовом ящике есть сообщения.
        /// </summary>
        public bool IsMessages
        {
          get 
          {
            return (NumberOfMessages > 0);
          }
        }
    
        /// <summary>
        /// Количество сообщений в ящике.
        /// </summary>
        public uint NumberOfMessages
        {
          get 
          {
            // not initialized
            if (_status == null)
            {
              GetStatus();
            }
    
            return _status.messages;
          }  
        }
        #endregion
    
        #region Method-Property substitution
            /// <summary>
            /// Получение количества сообщений.
            /// </summary>
            /// <returns></returns>
        public uint GetNumberOfMessages()
        {
                return NumberOfMessages;
        }
            
        public bool GetIsMessages()
        {
          return IsMessages;
        }
        #endregion
    
        /// <summary>
            /// Анализ количества  строк, полученных  от сервера после отправки команды STAT.    
        /// </summary>
            /// <example>Команда STAT. В ответ на вызов команды сервер выдает положительный ответ "+OK", 
            /// за которым следует количество сообщений в почтовом ящике и их общий размер в символах. 
            /// Сообщения, которые помечены для удаления, не учитываются в ответе сервера. 
            /// </example>
        void GetStatus()
        {
          CheckConnection();
    
          Send("STAT");
          string tmp = Receive();
    
          string [] tokens = tmp.Split(new Char[] {SPACE, CR}, 4);
    
          try
          {
            _status = new MaildropStatus(
              Convert.ToUInt32(tokens[1], 10), 
              Convert.ToUInt32(tokens[2], 10)
            );
          } 
          catch (Exception e)
          {
                    throw new CoreException("Невозможно проанализировать ответ", e);
          }
        }
            /// <summary>
            /// Установка соединения с сервером.
            /// </summary>
            /// <param name="server">Название сервера.</param>
            /// <param name="port">Номер порта.</param>
        void EstablishConnection(string server, int port)
        {
          // Получение IP-адреса сервера.
          IPAddress ipadr = Dns.Resolve(server).AddressList[0];
          IPEndPoint ephost = new IPEndPoint(ipadr, port);
     
          // Создание Socket для передачи данных по протоколу TCP.
          _socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
    
          
          LingerOption linger = new LingerOption(true, 10);
          _socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Linger, linger);
          // Установка времени ожидания.
          _socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.SendTimeout, SendTimeout);
          _socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout, ReceiveTimeout);
    
          // Соединение с сервером.
          _socket.Connect(ephost);
          if (!_socket.Connected)
          {
            throw new CoreException("Сервер не найден: " + server);
          }
        }
    
        /// <summary>
        /// Проверка соединения и авторизации пользователя.
        /// </summary>
        void CheckConnection()
        {
          if (_socket == null || !_socket.Connected) 
          {
            throw new CoreException("Соединение не установлено.");
          }
    
          if (!_authenticated)
          {
                    throw new CoreException("Пользователь не аутентифицирован (Метод LogIn). ");
          }
        }
            /// <summary>
            /// Отправка команды на сервер.
            /// </summary>
            /// <param name="command">Текст команды.</param>
        void Send(string command)
        {
                // Все команды заканчиваются парой CRLF.
          command += CRLF;
                // Сервер работает с кодировкой ASCII.
          Encoding tmp = Encoding.ASCII;
          Byte [] buf = tmp.GetBytes(command);
    
          int total = buf.Length;
          while (total > 0)
          {
            total -= _socket.Send(buf, command.Length, SocketFlags.None);
          }
        }
            /// <summary>
            /// Анализ POP3-строки.
            /// </summary>
            /// <param name="str">Строка.</param>
        void AnalyseResponse(string str)
        {
          Trace(str);
    //      Debug.WriteLine(str);
    
          if (str.StartsWith(STAT_ERR))
          {
            string msg;        
            int i = str.IndexOf(CRLF);
            if (i < 0) 
            {
              msg = "Ответ сервера: " + STAT_ERR;
            } 
            else
            {
              // Если ответ слишком большой, отсекаем  его.
              msg = str.Substring(STAT_ERR.Length + 1, Math.Min(i - STAT_ERR.Length - 1, 79));
            }
    
            throw new ResponseException(msg);
          }
        }
    
        /// <summary>
        /// Получение сообщения в POP3-формате.
        /// </summary>
        /// <param name="index">Номер сообщения.</param>
        /// <returns></returns>
        public StringReader DumpMessage(int index)
        {
          CheckConnection();
    
          Send("RETR " + index);
          return new StringReader(Receive());
        }
            /// <summary>
            /// Удаление символов конца сообщения.
            /// </summary>
            /// <param name="message">Сообщение.</param>
            /// <returns></returns>
        string TruncateTail(string message)
        {
          if (!message.EndsWith(FiveOctalTerm))
          {
            Debug.WriteLine("Последние 5 символов: {" + message.Substring(message.Length — 5) + "}");
            throw new ResponseException("Неправильные символы конца сообщения.");
          }
    
                return message.Remove(message.Length — FiveOctalTerm.Length, FiveOctalTerm.Length);
        }
    
        /// <summary>
        /// Получение существующих номеров сообщений.
        /// </summary>
        /// <returns>Массив с существующими индексами сообщений.</returns>
            /// <example>Команда LIST. Сервер выдает информацию о всех сообщениях, находящихся в почтовом ящике. 
            /// Сообщения, помеченные для удаления, не перечисляются. 
            /// </example>
        public uint[] ListMessages()
        {
          CheckConnection();
    
          if (_messagelist == null)
          {
            Send("LIST");
            string tmp = Receive();
            tmp = TruncateTail(tmp);
            int start = tmp.IndexOf(CRLF);
            if (start > 0)
            {
              start += CRLF.Length;
              ArrayList l = new ArrayList();
              Regex r = new Regex(@"\r\n");
              string [] list = r.Split(tmp.Substring(start));
              if (list.Length > 0)
              {
                foreach (string s in list)
                {
                  string [] f = s.Split(new char [] {' '}, 2);
                  l.Add(Convert.ToUInt32(f[0], 10));
                }
              }
    
              if (l.Count > 0)
              {
                _messagelist = (uint [])l.ToArray(typeof(uint));
              }
              else
                _messagelist = new uint[0];
            } else 
              _messagelist = new uint[0];
          }
    
          return _messagelist;
        }
    
        /// <summary>
        /// Отправляет команду NOOP на сервер. 
        /// </summary>
        /// <remarks>
        /// <para>Используется для поддержания сеанса с сервером.</para>
        /// </remarks>
            /// <example>Команда NOOP. POP3-сервер ничего не делает и всегда отвечает положительно. 
            /// </example>
        public void SendNoop()
        {
          CheckConnection();
    
          Send("NOOP");
          string tmp = Receive();
        }
    
        /// <summary>
        /// Возвращает уникальный идентификатор сообщения.
        /// </summary>
        /// <remarks>
            /// <para>
            /// Если сообщение помечено на удаление, оно не учитывается.
        /// </para>
        /// </remarks>
        /// <param name="index">Номер сообщения.</param>
        /// <returns>Уникальный идентификатор пользователя.</returns>
        public string GetMessageUniqueID(uint index)
        {
          CheckConnection();
    
          Send("UIDL " + index);
          string tmp = Receive();
    
          string [] f = tmp.Split(new char [] {' ', '\r', '\n'}, 4);
                return f[2];            
        }
    
        /// <summary>
        /// Получение заголовка сообщения.
        /// </summary>    
        /// <param name="index">Сообщение.</param>
        /// <param name="liens">Количество первых строк.</param>
        /// <returns>Сообщение с анализированными заголовками.</returns>
            /// <example>Команда TOP. Если ответ сервера положительный, 
            ///  он передает заголовки сообщения и указанное количество строк из тела сообщения.
            /// </example>
        public Message GetMessageHeader(uint index, int top)
        {
          CheckConnection();
    
          Send("TOP " + index + " " + top);
          string message = Receive();
    
          message = Utils.RemoveByteStuffedSequence(message);
          return new Message(this, TruncateTail(message), index);
        }
    
        /// <summary>Удаление сообщения.
        /// </summary>
        /// <param name="index">Номер сообщения.</param>
            /// <example>Команда DELETE. POP3-сервер помечает указанное сообщение как удаленное, 
            /// но не удаляет его, пока сессия не перейдет в режим UPDATE. 
            /// </example>
        public override void DeleteMessage(uint index)
        {
          CheckConnection();
    
          Send("DELE " + index);
          string tmp = Receive();
        }
    
        /// <summary>
        /// Получение сообщения.
        /// </summary>
        /// <param name="index">Номер сообщения.</param>
        /// <returns>Сообщение.</returns>
            /// <example>Команда RETR. После положительного ответа сервер передает содержание сообщения.        
            /// </example>
        public override Message GetMessage(uint index)
        {
          CheckConnection();
    
                Send("RETR " + index);
                string message = ReceiveMessage();
    
          message = Utils.RemoveByteStuffedSequence(message);
                return new Message(this, TruncateTail(message), index);
        }
    
        public void OnRecievedData( IAsyncResult ar )
        {
        }
    
            /// <summary>
            /// Получение ответа сервера без проверки подлинности.
            /// </summary>
            /// <returns>Ответ сервера.</returns>
        StringBuilder UnsafeReceive()
        {
          StringBuilder tmp = new StringBuilder();
          Encoding cenc = Encoding.ASCII;
          IAsyncResult asynResult;
          byte[] buf = new byte[1024];
          int recv = 0;      
          do
          {
            asynResult = _socket.BeginReceive(buf, 0, buf.Length, SocketFlags.None, null, null);
            if (asynResult.AsyncWaitHandle.WaitOne())
            {
              recv = _socket.EndReceive(asynResult);
              string t = cenc.GetString(buf, 0, recv);
              tmp.Append(t);
              if (t.LastIndexOf(FiveOctalTerm) > 0) break;
            }
          }
          while(_socket.Poll(PollTimeout, SelectMode.SelectRead));
    
                return tmp;
        }
        /// <summary>
        /// Получение ответа сервера без проверки подлинности.
        /// </summary>
        /// <returns>Ответ сервера.</returns>
        StringBuilder UnsafeReceiveMessage()
        {
          StringBuilder tmp = new StringBuilder();
          Encoding cenc = Encoding.ASCII;
          IAsyncResult asynResult;
          byte[] buf = new byte[1024];
          int recv = 0;      
          do
          {
            asynResult = _socket.BeginReceive(buf, 0, buf.Length, SocketFlags.None, null, null);
            if (asynResult.AsyncWaitHandle.WaitOne())
            {
              recv = _socket.EndReceive(asynResult);
              string t = cenc.GetString(buf, 0, recv);
              tmp.Append(t);
              //if (t.LastIndexOf(FiveOctalTerm) > 0) 
              //  break;
            }
          }
          while(!tmp.ToString().EndsWith(FiveOctalTerm));
    
          return tmp;
        }
        /// <summary>
        /// Возвращение  ответа сервера.
        /// </summary>
        /// <returns>Ответ сервера.</returns>
        string Receive()
        {
          StringBuilder tmp = UnsafeReceive();
                string str = tmp.ToString();
          AnalyseResponse(str);
    
          return str;
        }
        /// <summary>
        /// Возвращение сообщения в виде строки.
        /// </summary>
        /// <returns></returns>
        string ReceiveMessage()
        {
          StringBuilder tmp = UnsafeReceiveMessage();
          string str = tmp.ToString();
          AnalyseResponse(str);
    
          return str;
        }
            /// <summary>
            /// Аутентификация пользователя.
            /// </summary>
            /// <param name="username">Имя пользователя.</param>
            /// <param name="password">Пароль.</param>
            /// <example>После установки соединения сервер находится в режиме авторизации пользователя.
            /// Пользователь должен идентифицировать себя на сервере, используя команды USER и PASS. 
            /// Сначала надо отправить команду USER, после которой в качестве аргумента следует имя пользователя. 
            /// Если сервер отвечает положительно, то теперь необходимо отправить команду PASS, за которой следует пароль.
            /// <code>
            /// Client: USER username
            /// Server: +OK username
            /// Client: PASS mypass
            /// Server: +OK username
            /// </code>
            /// </example>
        void AuthenticateYourSelf(string username, string password)
        {
          Send("USER " + username);
          Receive();
                Send("PASS " + password);
          Receive();
    
          _authenticated = true;
        }
    
        /// <summary>
            /// Соединение с сервером и аутентификация пользователя.
        /// </summary>
        /// <param name="username">Имя пользователя.</param>
        /// <param name="password">Пароль.</param>
        public override void LogIn(string username, string password)
        {
          try
          {
            if (_socket != null) 
            {
              Quit();
              ResetVariables();
            }
                    // Установка соеденения.
            EstablishConnection(_server, _port);
            Receive(); // Получение приветствия от сервера.
            AuthenticateYourSelf(username, password);
          }
          catch (ShutdownException e)
          {
                    throw new CoreException("Невозможно завершить предыдущий сеанс.", e);
          }
          catch (Exception e)
          {
            throw new CoreException("Вход невозможен", e);
          }
        }
    
        /// <summary>
        /// Закрытие транзакции на сервере.
        /// </summary>
        public override void Quit()
        {
          try
          {
            CheckConnection();
                    // Сервер завершает POP3-сессию и переходит в режим UPDATE.
            Send("QUIT"); // Ответ нас не интересует
          }
          catch (Exception e)
          {
            throw new ShutdownException("Невозможно покинуть транзакцию", e);
          }
    
          CloseSocket();
        }
    
        /// <summary>
        /// Свойство закрытия соединения.
        /// </summary>
        void CloseSocket()
        {
          try
          {
            _socket.Shutdown(SocketShutdown.Both);
            _socket.Close();
            // Свойство 'Connected'  установлено в false, когда соединение закрыто.
            if (_socket.Connected) 
            {
              throw new CoreException("При закрытии socket возникло исключение: " + 
                Convert.ToString(System.Runtime.InteropServices.Marshal.GetLastWin32Error()));
            }
    
            _socket = null;
          }
          catch (SocketException e)
          {
                    throw new CoreException("Невозможно закрыть socket", e);
          }
        }
            /// <summary>
            /// Сброс переменных.
            /// </summary>
        void ResetVariables()
        {
          _authenticated = false;
          _status = null;
          _messagelist = null;
        }
    
        /// <summary>
        /// Закрытие сеанса.
        /// </summary>
        public override void Dispose()
        {
          try
          {
            Quit();
            ResetVariables();
          } 
          catch // Обработчик всех возникших исключений.
          {
            Debug.WriteLine("Невозможно закрыть socket");
          }
    
          GC.SuppressFinalize(this);
        }
      }
    }

    Класс Provider.cs

    namespace Mail.Providers
    {
      using System;
    
      /// <summary>
        /// Общий абстрактный класс для всех провайдеров.  
      /// </summary>
      public abstract class Provider : IDisposable
      {
            /// <summary>
            /// Название сервера.
            /// </summary>
        protected string _server;
            /// <summary>
            /// Номер порта.
            /// </summary>
        protected int _port;
        /// <summary>
        /// Временная папка для записи временных файлов.
        /// </summary>
        string _tempdir;
    
        /// <summary>
        /// Метод авторизации пользователя.
        /// </summary>
        /// <param name="login">Имя пользователя.</param>
        /// <param name="password">Пароль.</param>
        public abstract void LogIn(string login, string password);
    
        /// <summary>
        /// Закрытие сеанса.
        /// </summary>
        public abstract void Quit();
    
        /// <summary>
        /// Удаление сообщения.
        /// </summary>
        /// <param name="index">Номер сообщения.</param>
        public abstract void DeleteMessage(uint index);
    
        /// <summary>
        /// Получение сообщения.
        /// </summary>
            /// <param name="index">Номер сообщения.</param>
        public abstract Message GetMessage(uint index);
    
    
        /// <summary>
        /// Путь к временной папке.
        /// </summary>
        public string TempDirectory
        {
          get
          {
            return _tempdir;
          }
          set
          {
            _tempdir = value;
          }
        }
    
        /// <summary>
        /// Уничтожение объекта.
        /// </summary>
        abstract public void Dispose();
      }
    }

    Обработка вложений. Класс AttachDescriptor.cs

    using System;
    using System.IO;
    using System.Security.Cryptography;
    using System.Text;
    
    namespace Mail
    {
      /// <summary>
        /// Содержит методы и информацию о вложениях в письмо.
      /// </summary>
      public class AttachDescriptor
      {
        string _oldname;
        string _tmpfile;
    
        internal AttachDescriptor(string name, string dir)
        {
          _oldname = name;
          _tmpfile = dir + Guid.NewGuid();
        }
        /// <summary>
        /// Декодирование  файла.
        /// </summary>
        /// <param name="message">Текст сообщения с вложенным файлом.</param>
        /// <param name="transform">Формат трансформации.</param>
        internal void DecodeFile(string message, ICryptoTransform transform)
        {
          try 
          {
            // Создаем временный файл.
            FileStream tf = new FileStream(_tmpfile, FileMode.Create, FileAccess.Write);
            // Создаем поток трансформации для временного файла.
            CryptoStream cs = new CryptoStream(tf, transform, CryptoStreamMode.Write);
            
            // Конвертируем  строки в массив байтов
            Encoding enc = Encoding.ASCII;
            byte [] b = enc.GetBytes(message);
            // Записываем байты в поток трансформации.
            cs.Write(b, 0, b.Length);
            // Закрываем потоки.
            cs.Close();
            tf.Close();
          } 
          // Обрабатываем  возникшие исключения.
          catch(System.Exception e)
          {
            Console.WriteLine(e.ToString());
            throw new ParseException("Невозможно декодировать содержимое файла", e);
          }
        }
        /// <summary>
        /// Закрываем  и удаляем  временный файл.
        /// </summary>
        internal void Close()
        {
          File.Delete(_tmpfile);            
        }
    
        /// <summary>
            /// Возвращаем  файловый поток из  файла временного вложения.
        /// </summary>
        /// <returns></returns>
        public FileStream GetFile()
        {
          FileStream tf = new FileStream(_tmpfile, FileMode.Open, FileAccess.Read);
          return tf;
        }
    
        #region Public properties
            /// <summary>
            /// Название.
            /// </summary>
        public string Name
        {
          get
          {
                    return _oldname;
          }
        }
            /// <summary>
            /// Временный файл.
            /// </summary>
        public string TempFile
        {
          get
          {
            return _tmpfile;
          }
        }
            /// <summary>
            /// Размер.
            /// </summary>
        public long Size
        {
          get
          {
            FileInfo fi = new FileInfo(_tmpfile);
            return fi.Length;
          }
        }
        #endregion
      }
    }

    Основной класс сообщения. Common.cs

    namespace Mail
    {
      using System;
      using System.Collections;
      using System.IO;
      using System.Text;
      using System.Text.RegularExpressions;
      using System.Security.Cryptography;
    
      using Mail.Providers;
    
      /// <summary>
      /// Основной класс для <see cref="Mime"/> и <see cref="Message"/>.
      /// Содержит общую информацию и различные методы.
      /// </summary>
      public class Common
      {
        internal const string DCRLF = "\r\n\r\n";
        internal const string CRLF = "\r\n";
        internal const char Colon = ':';
        internal const string MIMEE = "--";
    
        internal string _message;
        internal long _size;
    
        internal Provider _pop3;
    
        public Provider Parent
        {
          get
          {
            return _pop3;
          }      
        }
    
        /// <summary>
        /// Список sub-mimes.
        /// </summary>
        public Mime [] ChildMimes = new Mime[0];
    
        /// <summary>
        /// Заголовки.
        /// </summary>
        internal Hashtable Headers = new Hashtable();
    
        /// <summary>
            /// Содержит все заголовки из <see cref="Message"/> или <see cref="Mime"/>
        /// </summary>
        /// <remarks>
            /// Все заголовки должны быть в нижнем регистре.
        /// </remarks>
        public Hashtable AllHeaders
        {
          get
          {
                    return Headers;
          }
        }
    
        /// <summary>
        /// Размер сообщения.
        /// </summary>
        public long GetSize()
        {
          return _size;      
        }
        /// <summary>
        /// Подготовка  строки в зависимости от кодировки сообщения.
        /// </summary>
        /// <param name="mes">Текст сообщения.</param>
        /// <returns></returns>
        internal string PreparedString(string mes)
        {
          string t;
          switch (TransferEncoding)
          {
            case "base64":
              t = DecodeMessage(mes, new FromBase64Transform());
              break;
    
            case "quoted-printable":
              t = DecodeMessage(mes, new FromQuotedPrintableTransform());
              break;
    
            default:
              t = mes;
              break;
          }
    
          return t;
        }
        /// <summary>
        /// Подготовка  тела сообщения.
        /// </summary>
        /// <returns></returns>
        internal string PreparedBody()
        {
          
          return PreparedString(_message);
        }
        /// <summary>
        /// Декодируем сообщение.
        /// </summary>
        /// <param name="message">Текст сообщения.</param>
        /// <param name="transform">Тип трансформации.</param>
        /// <returns></returns>
        string DecodeMessage(string message, ICryptoTransform transform)
        {
          MemoryStream tf = new MemoryStream();
          CryptoStream cs = new CryptoStream(tf, transform, CryptoStreamMode.Write);
            
          // конвертируем  строки в массив байтов
          Encoding enc = Encoding.ASCII;
          byte [] b = enc.GetBytes(message);
          cs.Write(b, 0, b.Length);
    
          cs.Close();
          string t = Utils.GetEncoding(Charset).GetString(tf.ToArray());
          tf.Close();
          return t;
        }
        /// <summary>
        /// Конструктор.
        /// </summary>
        /// <param name="parent">Родительский провайдер.</param>
        /// <param name="message">Текст, содержащий сообщение.</param>
        internal Common(Provider parent, string message)
        {
          if (parent == null)
          {
            throw new ArgumentNullException("parent");
          }
          if (message == String.Empty)
          {
            throw new ArgumentException("empty string", "message");
          }
    
          int end = FillHeaders(message);
          _size = message.Length;
    
          // исключаем заголовок из тела сообщения
          _message = message.Substring(end);
          _pop3 = parent;
        }
    
        /// <summary>
            /// Выбираем все заголовки и заполняем массив.
        /// </summary>
        /// <returns></returns>
        internal int FillHeaders(string message)
        {
          int start = 0; //message.IndexOf(CRLF) + CRLF.Length; //пропускаем 2 байта
          int headerend = message.IndexOf(DCRLF); 
          string headers = message.Substring(start, headerend - start);
          GetHeaders(headers);
    
          // пропускаем секцию заголовков
          headerend += DCRLF.Length;
    
          return headerend;
        }
    
        /// <summary>
        /// Заполнение  <see cref="Mime"/> массива.
        /// </summary>
        /// <returns></returns>
        protected bool MultipartMixed()
        {
          string b = GetBoundary();
          if (b == String.Empty) return false;
    
          int s = _message.IndexOf(b);
          if (s < 0)
          {
            throw new ParseException("Can't find beginning MIME boundary: " + b);
          }
    
          ArrayList tmimes = new ArrayList();
          
          while(true)
          {
            s += b.Length + CRLF.Length;
    
            int e = _message.IndexOf(b, s);
            if (e < 0)
            {          
              if (_message.IndexOf(MIMEE, s - CRLF.Length, MIMEE.Length) < 0)
              {
                throw new ParseException("Неправильный MIME");
              }
    
              break;
            }
                          
    
            tmimes.Add(new Mime(_pop3, _message.Substring(s, e - s - CRLF.Length)));
            s = e;
          }
    
          ChildMimes = (Mime [])tmimes.ToArray(typeof(Mime));
                
          return true;
        }
    
    
        /// <summary>
        /// Попытка извлечения значения 'boundary' из <see cref="ContentType"/>.
        /// </summary>
        /// <returns></returns>
        protected string GetBoundary()
        {      
          Regex r = new Regex("boundary=[\\\"]?([^\\r\\\"]+)");
          if (ContentType == null)
          {
                    return String.Empty;
          }
    
          Match m = r.Match(ContentType);
          if (m.Success)
          {
            return "--" + m.Groups[1].ToString();
          }
          else
          {
            return String.Empty;
          }
        }
    
    
    
        /// <summary>
        /// Все заголовки в нижнем регистре.
        /// </summary>
        /// <param name="top">Заголовок</param>
        void GetHeaders(string top)
        {      
          Regex line = new Regex(@"\r\n(?![\t\x20])");
          string [] col = line.Split(top);
          foreach (string s in col)
          {
            string [] fields = s.Split(new Char[] {':'}, 2);
            //        Console.WriteLine(fields[0] + "}={" + fields[1] + "}");
            if (fields.Length < 2) continue;
            fields[0] = fields[0].ToLower(); // перевод в нижний регистр
            fields[1] = fields[1].TrimStart(' '); // удаление ненужных пробелов
    
            
            if (Headers.ContainsKey(fields[0]))
            {
              object oldv = Headers[fields[0]];
              ArrayList al = oldv as ArrayList;
              if (al == null)
              {
                al = new ArrayList();
                al.Add(oldv); 
                Headers[fields[0]] = al;
              } 
    
              al.Add(fields[1]);
            } 
            else 
            {
              Headers.Add(fields[0].ToLower(), fields[1]);
            }
          }
        }
    
        #region Common headers
        public string Charset
        {
          get
          {
            Regex r = new Regex(@"charset=[""'\s]([^""'\s]+)");
            Match m = r.Match(ContentType);
            if (m.Success)
              return m.Groups[1].Value;
            else
              return "";
          }
        }
    
        protected string TransferEncoding
        {
          get
          {
            return ((string)Headers["content-transfer-encoding"]).ToLower();
          }
        }
    
        /// <summary>
        /// Содержит тип текущей <see cref="Mime"/> секции или <see cref="Message"/>.
        /// </summary>    
        public string ContentType
        {
          get
          {
            return (string)Headers["content-type"];
          }
        }
        #endregion
      }
    }

    Класс Message.cs

    namespace Mail
    {
      using System;
      using System.Text;
      using System.Text.RegularExpressions;
      using System.Collections;
      using System.Diagnostics;
    
      using Mail.Providers;
      /// <summary>
      /// Класс, который описывает сообщение, полученное с сервера.  
      /// </summary>
      public class Message : Common, IDisposable
      {
        string _body;
        // Тип тела сообщения.
        BodyTypes _body_type = BodyTypes.Unknown;
        // Массив вложений.
        AttachDescriptor [] _attaches = null;
    
        /// <summary>
        /// Номер сообщения.
        /// </summary>
        public uint Index;
    
    
        /// <summary>
        /// Создание  нового сообщения.
        /// </summary>
        /// <param name="parent">Ссылка на провайдер.</param>
        /// <param name="message">Текст сообщения, которое необходимо проанализировать.</param>
        /// <param name="index">Номер сообщения.</param>
        public Message(Provider parent, string message, uint index) : base(parent, message)
        {
          // Если индекс сообщения меньше нуля, то генерируется исключение типа ArgumentOutOfRangeException
          if (index < 1)
          {
            throw new ArgumentOutOfRangeException("index");
          }
    
          Index = index;
          ParseContentType();
        }
    
        /// <summary>
        /// Вложенные файлы.
        /// </summary>
        public AttachDescriptor [] Attachments
        {
          get
          {
            if (_attaches == null)
            {
              ArrayList al = new ArrayList();
                        GetAllAttachments(ChildMimes, al);
              _attaches = (AttachDescriptor [])al.ToArray(typeof(AttachDescriptor));
            }
    
            return _attaches;
          }
        }
    
        /// <summary>
        /// Получение всех вложений.
        /// </summary>
        /// <param name="mimes"></param>
        void GetAllAttachments(Mime [] mimes, ArrayList al)
        {
          foreach (Mime m in mimes)
          {
            if (m.ChildMimes.Length == 0)
            {
              if (m._attach != null) al.Add(m._attach);
            } 
            else
            {
              GetAllAttachments(m.ChildMimes, al);
            }
          }
        }
      
        // Анализ типа сообщения.
        void ParseContentType()
        {
          if (ContentType == null)
          {
                    throw new ParseException("Определение типа сообщения (Content-Type пуст)");
          }
    
          string type;
          int i = ContentType.IndexOf(";");
          if (i < 0)
          {
            type = ContentType;
          }
          else
          {
                    type = ContentType.Substring(0, i);
          }
          // В зависимости от типа сообщения анализируем текст и выбираем вложения.
          switch(type)
          {
            case "multipart/mixed":
              MultipartMixed();
              break;
    
            case "multipart/alternative":
              MultipartMixed();
              break;
    
            case "multipart/related":
              MultipartMixed();
              break;
    
            case "text/html":
              _body = _message;
              _body_type = BodyTypes.HTML;
              break;
    
            case "text/plain":
              _body = _message;
              _body_type = BodyTypes.Text;
              break;
          }
        }
    
        /// <summary>
            /// Анализирует строку для получения e-mail.    
        /// </summary>
        /// <param name="mail">Строка с адресом</param>
        /// <returns>адрес типа [mail@host.com], [mail@localhost] или [host@123.123.123.123]</returns>
        public string ExtractEmailFromAddress(string mail)
        {
          // mail@(ip)|(host)
          Regex ex = new Regex(@"([a-zA-Z0-9_\-\.]+)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([a-zA-Z0-9\-]+\.?)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)");
          Match m = ex.Match(mail);
          if (!m.Success) 
          {
            throw new ParseException("email не найден.");
          }
    
          return m.ToString();
        }
    
        public void Dispose()
        {
          foreach(AttachDescriptor ad in Attachments)
          {
                    ad.Close();
          }            
    
          _attaches = null;
          _body = null;
          _message = null;
          Headers = null;
          ChildMimes = null;
    
          GC.SuppressFinalize(this);
        }
        /// <summary>
        /// Перегруженный метод ToString. Возвращает информацию о сообщении.
        /// </summary>
        /// <returns></returns>
        public override string ToString()
        {
          StringBuilder sb = new StringBuilder();
    
          sb.AppendFormat("Size: {0}b\r\n", GetSize());
          sb.AppendFormat("From: '{0}', email: '{1}'\r\n", From, FromEmail);
          sb.AppendFormat("Subject: '{0}'\r\n", Subject);
    
          if (Attachments.Length > 0)
          {
            sb.Append("Attachments:\r\n");
    
            foreach(AttachDescriptor ad in Attachments)
            {
              sb.Append("\tName: " + ad.Name + " Size: " + ad.Size + "\r\n");
            }
          }
    
          return sb.ToString();
        }
        // 
        /// <summary>
        /// Возможные типы тела сообщения.
        /// </summary>
        public enum BodyTypes
        {
          Unknown,
                HTML,
          Text
        }
    
        /// <summary>
        /// Возвращение  тела сообщения из MIME.
        /// </summary>
        /// <param name="type">Тип тела сообщения.</param>
        /// <param name="mimes">MIME</param>
        /// <returns></returns>
        string GetBodyFromMime(BodyTypes type, Mime [] mimes)
        {
          foreach (Mime m in mimes)
          {
            if (m.ChildMimes.Length == 0)
            {
              switch(type)
              {
                case BodyTypes.HTML:
                  if (m.ContentType.IndexOf("text/html") > -1)
                  {
                    return m.PreparedBody();
                  }
                  break;
    
                case BodyTypes.Text:
                  if (m.ContentType.IndexOf("text/plain") > -1)
                  {
                    return m.PreparedBody();
                  }
                  break;
              }
            } 
            else
            {
              string r = GetBodyFromMime(type, m.ChildMimes);
              if (r != "") return r;
            }
          }
    
          return "";
        }
    
        /// <summary>
        /// Открытый метод, возвращающий тело сообщения.
        /// </summary>
        /// <param name="type">Тип тела сообщения.</param>
        /// <returns></returns>
        public string GetBody(BodyTypes type)
        {
          if (_body_type == BodyTypes.Unknown)
            return GetBodyFromMime(type, ChildMimes);
          else
            return PreparedString(_body);
    
        }
    
        /// <summary>
        /// Возвращение тела сообщения.
        /// </summary>
        /// <returns></returns>
        public string Text
        {
          get
          {
            string text;
            if (_body_type == BodyTypes.Unknown)
            {
              text = GetBodyFromMime(BodyTypes.Text, ChildMimes);
              if (text == null || text.Trim() == "")
                text = Utils.ExtractTextFromHtml(GetBodyFromMime(BodyTypes.HTML, ChildMimes));
            }
            else
            {
              text = PreparedString(_body);
                        if (_body_type == BodyTypes.HTML) 
                text = Utils.ExtractTextFromHtml(text);
            }
    
            return text.Trim();
          }
        }
    
        #region Common headers
            /// <summary>
            /// Организация.
            /// </summary>
        public string Organization
        {
          get
          {
            return (string)Headers["organization"];
          }
        }
    
        /// <summary>
        /// Копии письма.
        /// </summary>    
        public string CC
        {
          get
          {
            return (string)Headers["cc"];
          }
        }
    
        /// <summary>
        /// Дата сообщения.
        /// </summary>
        public string Date
        {
          get
          {
            return (string)Headers["date"];
          }
        }
    
        /// <summary>
        /// Адрес отправителя.
        /// </summary>
        public string ReturnPath
        {
          get
          {
            return (string)Headers["return-path"];
          }
        }
    
        /// <summary>
        /// Адрес отправителя.
        /// </summary>    
        public string From
        {
          get
          {
                    return (string)Headers["from"];
          }
        }
            /// <summary>
            /// От кого.
            /// </summary>
        public string FromEmail
        {
          get
          {
            return ExtractEmailFromAddress((string)Headers["from"]);
          }
        }
            /// <summary>
            /// Кому
            /// </summary>
        public string To
        {
          get
          {
            return (string)Headers["to"];
          }
        }
            /// <summary>
            /// Тема
            /// </summary>
        public string Subject
        {
          get
          {
            return Utils.WordDecoder((string)Headers["subject"]);
          }
        }
            /// <summary>
            /// Повтор
            /// </summary>
        public string ReplyTo
        {
          get
          {
            return (string)Headers["reply-to"];
          }
        }
        #endregion
      }
    }

    Класс Mime.cs

    //#define _DEBUG
    
    namespace Mail
    {
      using System;
      using System.Diagnostics;
      using System.Text;
      using System.IO;
      using System.Text.RegularExpressions;
      using System.Security.Cryptography;
    
      using Mail.Providers;
    
      public class Mime : Common
      {
        #region DEBUG
        FileStream GetDebugStream()
        {
          return new FileStream(@"C:\trace_mimes.log", FileMode.Append);
        }
        [Conditional("_DEBUG")]
        void Trace(string str)
        {
          FileStream fs = GetDebugStream();
          byte [] b = Encoding.ASCII.GetBytes(str);
          fs.Write(b, 0, b.Length);
          fs.Close();
        }
        #endregion
    
        internal AttachDescriptor _attach = null;
    
        /// <summary>
        /// Конструктор.
        /// </summary>
        /// <param name="pm">Провайдер.</param>
        /// <param name="message">Текст сообщения.</param>
        internal Mime(Provider pm, string message) : base(pm, message)
        {      
                // если MIME не содержит MultipartMixed, то осуществляется попытка  проверки на наличие вложений
          if (!MultipartMixed())
          {
            FindAttachment();
          }
        }
        /// <summary>
        /// Определение  вложения сообщения.
        /// </summary>
        void FindAttachment()
        {
          // Если вложения нет, возвращаемся назад
          if (ContentDisposition == null) 
          {
                    return;
          }
    
          string [] cd = ContentDisposition.Split(new char [] {';'}, 2);
          switch(cd[0].ToLower())
          {
                    case "attachment":
              ExtractAttachment(cd[1]);
              break;
                    
            case "inline":
              throw new CoreException("не реализовано");
    
            default:
              throw new ParseException("Неизвестный ContentDisposition:" + cd[0]);
          }
        }
        /// <summary>
        /// Получение имени вложенного файла.
        /// </summary>
        /// <param name="filename"></param>
        /// <returns></returns>
        string GetAttachmentFilename(string filename)
        {
          Regex r = new Regex("filename=[\\\"]?([^\\r\\\"]+)");
          Match m = r.Match(filename);
          if (!m.Success)
          {
                    return String.Empty;
          }      
    
          return Utils.WordDecoder(m.Groups[1].ToString());
        }
        /// <summary>
        /// Извлечение прикрепленных файлов из сообщения.
        /// </summary>
        /// <param name="filename">Название временного файла.</param>
        void ExtractAttachment(string filename)
        {
          _attach = new AttachDescriptor(GetAttachmentFilename(filename), _pop3.TempDirectory);
    
          switch (TransferEncoding)
          {
            case "base64":
              _attach.DecodeFile(_message, new FromBase64Transform());
              break;
    
            case "quoted-printable":
              _attach.DecodeFile(_message, new FromQuotedPrintableTransform());
              break;
    
            default:
                        Debug.WriteLine("Неизвестный тип кодировки.");
              break;
          }
        }
    
        #region Common headers
        /// <summary>
        /// Возвращение  заголовка content-disposition, сообщающего о вложении.
        /// </summary>
        string ContentDisposition
        {
          get
          {
            return (string)Headers["content-disposition"];
          }
        }
        #endregion
      }
    }

    Отправка сообщений — проект SendMail

    Основной листинг MailSender.cs:

    using System;
    using System.Web.Mail;
    
    namespace Mail
    {
      /// <summary>
      /// Класс, отвечающий за отправку почты.
      /// </summary>
      /// <example>
      /// MailSender mailSender = new MailSender("smtp.someserver.com");
      /// MailMessage message = new MailMessage();
      /// message.From = "from@someserver.com";
      /// message.To = "to@someserver.com";
      /// message.Subject = "subject";
      /// message.Body = "body text";
      /// message.BodyFormat = MailFormat.Text;
      /// mailSender.Send(message);
      /// </example>
      public class MailSender
      {
        private string _server;
        
        /// <summary>
        /// Конструктор.
        /// </summary>
        /// <param name="server">SMTP-сервер.</param>    
        public MailSender(string server)
        {
          this._server = server;      
        }
    
        /// <summary>
        /// Отправка почты.
        /// </summary>
        /// <param name="message">Письмо.</param>
        public void Send(MailMessage message)
        {
          // Инициализируем сервер отправки сообщений.
          SmtpMail.SmtpServer = this._server;
          // Отправляем сообщение.
          SmtpMail.Send(message);
        }
    
        /// <summary>
        /// Отправка почты с паролем.
        /// </summary>
        /// <param name="message">Письмо.</param>
        /// <param name="password">Пароль пользователя.</param>
        public void Send(MailMessage message, string password)
        {
          // Добавляем к сообщению имя пользователя и пароль на тот случай,
          // когда сервер исходящей почты требует аутентификацию.
          message.Fields.Add("http://schemas.microsoft.com/cdo/configuration/smtpauthenticate", 1);
          message.Fields.Add("http://schemas.microsoft.com/cdo/configuration/sendusername", message.From); 
          message.Fields.Add("http://schemas.microsoft.com/cdo/configuration/sendpassword", password);
          // Отправляем сообщение.
          this.Send(message);
        }
      }
    }

    Интерфейс программы Ballet — проект MailApplication.

    Создание новой учетной записи. Форма-контейнер Мастера

    Форма CreateUserWizard представляет собой родительский контейнер для помещения в нее форм — шагов Мастера (см. рис. 3.25)

    using System;
    using System.Drawing;
    using System.Collections;
    using System.ComponentModel;
    using System.Windows.Forms;
    
    namespace MailApplication
    {
      /// <summary>
      /// Summary description for CreateUserWizard.
      /// </summary>
      public class CreateUserWizard : System.Windows.Forms.Form
      {
        /// <summary>
        /// Required designer variable.
        /// </summary>
        private System.ComponentModel.Container components = null;
    
        public CreateUserWizard()
        {
          //
          // Required for Windows Form Designer support
          //
          InitializeComponent();
    
          //
          // TODO: Add any constructor code after InitializeComponent call
          //
        }
    
        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        protected override void Dispose( bool disposing )
        {
          if( disposing )
          {
            if(components != null)
            {
              components.Dispose();
            }
          }
          base.Dispose( disposing );
        }
    
        #region Windows Form Designer generated code
        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
          System.Resources.ResourceManager resources = new System.Resources.ResourceManager(typeof(CreateUserWizard));
          // 
          // CreateUserWizard
          // 
          this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
          this.ClientSize = new System.Drawing.Size(392, 266);
          this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
          this.IsMdiContainer = true;
          this.Name = "CreateUserWizard";
          this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
          this.Text = "Создание новый учетной записи";
          this.Load += new System.EventHandler(this.CreateUserWizard_Load);
    
        }
        #endregion
    
        private void CreateUserWizard_Load(object sender, System.EventArgs e)
        {
          UserIdentity identity = new UserIdentity();      
          CUWStep1 step1 = new CUWStep1(identity);
          step1.MdiParent = this;
          step1.Show();
        }
      }
    }

    Первый шаг Мастера. Форма CUWStep1.cs

    Значения свойства Name элементов управления этой формы приведены на рис. 3.27:

    (рис 3.27) Форма CUWStep1

    Полный листинг формы:

    using System;
    using System.Drawing;
    using System.Collections;
    using System.ComponentModel;
    using System.Windows.Forms;
    
    namespace MailApplication
    {
      /// <summary>
      /// Summary description for CUWStep1.
      /// </summary>
      public class CUWStep1 : System.Windows.Forms.Form
      {
        private UserIdentity identity;
        private System.Windows.Forms.Label lblEmail;
        private System.Windows.Forms.TextBox txbEmail;
        private System.Windows.Forms.Label lblMailSample;
        private System.Windows.Forms.Label lblAliasSample;
        private System.Windows.Forms.TextBox txbAlias;
        private System.Windows.Forms.Label lblAlias;
        private System.Windows.Forms.Button btnNext;
        /// <summary>
        /// Required designer variable.
        /// </summary>
        private System.ComponentModel.Container components = null;
    
        public CUWStep1(UserIdentity identity)
        {      
          InitializeComponent();
    
          this.identity = identity;
        }
    
        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        protected override void Dispose( bool disposing )
        {
          if( disposing )
          {
            if(components != null)
            {
              components.Dispose();
            }
          }
          base.Dispose( disposing );
        }
    
        #region Windows Form Designer generated code
        /// <summary>
        /// Required method for Designer support — do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
          System.Resources.ResourceManager resources = new System.Resources.ResourceManager(typeof(CUWStep1));
          this.lblEmail = new System.Windows.Forms.Label();
          this.txbEmail = new System.Windows.Forms.TextBox();
          this.lblMailSample = new System.Windows.Forms.Label();
          this.lblAliasSample = new System.Windows.Forms.Label();
          this.txbAlias = new System.Windows.Forms.TextBox();
          this.lblAlias = new System.Windows.Forms.Label();
          this.btnNext = new System.Windows.Forms.Button();
          this.SuspendLayout();
          // 
          // lblEmail
          // 
          this.lblEmail.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
            | System.Windows.Forms.AnchorStyles.Right)));
          this.lblEmail.Location = new System.Drawing.Point(24, 16);
          this.lblEmail.Name = "lblEmail";
          this.lblEmail.Size = new System.Drawing.Size(240, 23);
          this.lblEmail.TabIndex = 0;
          this.lblEmail.Text = "Введите адрес электронной почты";
          this.lblEmail.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
          // 
          // txbEmail
          // 
          this.txbEmail.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
            | System.Windows.Forms.AnchorStyles.Right)));
          this.txbEmail.Location = new System.Drawing.Point(24, 48);
          this.txbEmail.Name = "txbEmail";
          this.txbEmail.Size = new System.Drawing.Size(240, 20);
          this.txbEmail.TabIndex = 1;
          this.txbEmail.Text = "";
          // 
          // lblMailSample
          // 
          this.lblMailSample.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
            | System.Windows.Forms.AnchorStyles.Right)));
          this.lblMailSample.ForeColor = System.Drawing.SystemColors.AppWorkspace;
          this.lblMailSample.Location = new System.Drawing.Point(24, 72);
          this.lblMailSample.Name = "lblMailSample";
          this.lblMailSample.Size = new System.Drawing.Size(240, 23);
          this.lblMailSample.TabIndex = 2;
          this.lblMailSample.Text = "Например, address@mail.com";
          this.lblMailSample.TextAlign = System.Drawing.ContentAlignment.TopRight;
          // 
          // lblAliasSample
          // 
          this.lblAliasSample.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
            | System.Windows.Forms.AnchorStyles.Right)));
          this.lblAliasSample.ForeColor = System.Drawing.SystemColors.AppWorkspace;
          this.lblAliasSample.Location = new System.Drawing.Point(26, 160);
          this.lblAliasSample.Name = "lblAliasSample";
          this.lblAliasSample.Size = new System.Drawing.Size(240, 23);
          this.lblAliasSample.TabIndex = 5;
          this.lblAliasSample.Text = "Например, Иван Васильевич";
          this.lblAliasSample.TextAlign = System.Drawing.ContentAlignment.TopRight;
          // 
          // txbAlias
          // 
          this.txbAlias.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
            | System.Windows.Forms.AnchorStyles.Right)));
          this.txbAlias.Location = new System.Drawing.Point(26, 136);
          this.txbAlias.Name = "txbAlias";
          this.txbAlias.Size = new System.Drawing.Size(240, 20);
          this.txbAlias.TabIndex = 2;
          this.txbAlias.Text = "";
          // 
          // lblAlias
          // 
          this.lblAlias.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
            | System.Windows.Forms.AnchorStyles.Right)));
          this.lblAlias.Location = new System.Drawing.Point(26, 104);
          this.lblAlias.Name = "lblAlias";
          this.lblAlias.Size = new System.Drawing.Size(240, 23);
          this.lblAlias.TabIndex = 3;
          this.lblAlias.Text = "Введите ваше имя ";
          this.lblAlias.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
          // 
          // btnNext
          // 
          this.btnNext.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
          this.btnNext.Location = new System.Drawing.Point(192, 192);
          this.btnNext.Name = "btnNext";
          this.btnNext.TabIndex = 3;
          this.btnNext.Text = "Далее";
          this.btnNext.Click += new System.EventHandler(this.btnNext_Click);
          // 
          // CUWStep1
          // 
          this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
          this.ClientSize = new System.Drawing.Size(292, 238);
          this.ControlBox = false;
          this.Controls.Add(this.btnNext);
          this.Controls.Add(this.lblAliasSample);
          this.Controls.Add(this.txbAlias);
          this.Controls.Add(this.txbEmail);
          this.Controls.Add(this.lblAlias);
          this.Controls.Add(this.lblMailSample);
          this.Controls.Add(this.lblEmail);
          this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
          this.Name = "CUWStep1";
          this.Text = "Шаг 1 из 3";
          this.WindowState = System.Windows.Forms.FormWindowState.Maximized;
          this.ResumeLayout(false);
    
        }
        #endregion
    
        private void btnNext_Click(object sender, System.EventArgs e)
        {
          if(txbEmail.Text == "")
          {
            MessageBox.Show("Введите адрес электронной почты.");
            return;
          }
          else
          {
            identity.Alias = txbAlias.Text;
            identity.Mail = txbEmail.Text;
            
            CUWStep2 step2 = new CUWStep2(this.identity);
            step2.MdiParent = this.MdiParent;
            this.Close();
            step2.Show();
          }
        }
    
        
      }
    }

    Второй шаг Мастера. Форма CUWStep2.cs

    Значения свойства Name элементов управления этой формы приведены на рис. 3.28.

    (рис 3.28) Форма CUWStep2

    Полный листинг формы:

    using System;
    using System.Drawing;
    using System.Collections;
    using System.ComponentModel;
    using System.Windows.Forms;
    
    namespace MailApplication
    {
      /// <summary>
      /// Summary description for CUWStep2.
      /// </summary>
      public class CUWStep2 : System.Windows.Forms.Form
      {
        private UserIdentity identity;
        private System.Windows.Forms.Label lblPop3Sample;
        private System.Windows.Forms.TextBox txbPop3;
        private System.Windows.Forms.Label lblPop3;
        private System.Windows.Forms.Label lblPop3PortSample;
        private System.Windows.Forms.TextBox txbPop3Port;
        private System.Windows.Forms.Label lblPop3Port;
        private System.Windows.Forms.Button btnNext;
        /// <summary>
        /// Required designer variable.
        /// </summary>
        private System.ComponentModel.Container components = null;
    
        public CUWStep2(UserIdentity identity)
        {      
          InitializeComponent();
    
          this.identity = identity;
        }
    
        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        protected override void Dispose( bool disposing )
        {
          if( disposing )
          {
            if(components != null)
            {
              components.Dispose();
            }
          }
          base.Dispose( disposing );
        }
    
        #region Windows Form Designer generated code
        /// <summary>
        /// Required method for Designer support — do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
          System.Resources.ResourceManager resources = new System.Resources.ResourceManager(typeof(CUWStep2));
          this.lblPop3Sample = new System.Windows.Forms.Label();
          this.txbPop3 = new System.Windows.Forms.TextBox();
          this.lblPop3 = new System.Windows.Forms.Label();
          this.lblPop3PortSample = new System.Windows.Forms.Label();
          this.txbPop3Port = new System.Windows.Forms.TextBox();
          this.lblPop3Port = new System.Windows.Forms.Label();
          this.btnNext = new System.Windows.Forms.Button();
          this.SuspendLayout();
          // 
          // lblPop3Sample
          // 
          this.lblPop3Sample.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
            | System.Windows.Forms.AnchorStyles.Right)));
          this.lblPop3Sample.ForeColor = System.Drawing.SystemColors.AppWorkspace;
          this.lblPop3Sample.Location = new System.Drawing.Point(26, 64);
          this.lblPop3Sample.Name = "lblPop3Sample";
          this.lblPop3Sample.Size = new System.Drawing.Size(240, 23);
          this.lblPop3Sample.TabIndex = 5;
          this.lblPop3Sample.Text = "Например, pop3.mail.com";
          this.lblPop3Sample.TextAlign = System.Drawing.ContentAlignment.TopRight;
          // 
          // txbPop3
          // 
          this.txbPop3.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
            | System.Windows.Forms.AnchorStyles.Right)));
          this.txbPop3.Location = new System.Drawing.Point(26, 40);
          this.txbPop3.Name = "txbPop3";
          this.txbPop3.Size = new System.Drawing.Size(240, 20);
          this.txbPop3.TabIndex = 4;
          this.txbPop3.Text = "";
          // 
          // lblPop3
          // 
          this.lblPop3.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
            | System.Windows.Forms.AnchorStyles.Right)));
          this.lblPop3.Location = new System.Drawing.Point(26, 8);
          this.lblPop3.Name = "lblPop3";
          this.lblPop3.Size = new System.Drawing.Size(240, 23);
          this.lblPop3.TabIndex = 3;
          this.lblPop3.Text = "Введите адрес  сервера POP3:";
          this.lblPop3.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
          // 
          // lblPop3PortSample
          // 
          this.lblPop3PortSample.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
            | System.Windows.Forms.AnchorStyles.Right)));
          this.lblPop3PortSample.ForeColor = System.Drawing.SystemColors.AppWorkspace;
          this.lblPop3PortSample.Location = new System.Drawing.Point(26, 160);
          this.lblPop3PortSample.Name = "lblPop3PortSample";
          this.lblPop3PortSample.Size = new System.Drawing.Size(240, 23);
          this.lblPop3PortSample.TabIndex = 8;
          this.lblPop3PortSample.Text = "Например, 110";
          this.lblPop3PortSample.TextAlign = System.Drawing.ContentAlignment.TopRight;
          // 
          // txbPop3Port
          // 
          this.txbPop3Port.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
            | System.Windows.Forms.AnchorStyles.Right)));
          this.txbPop3Port.Location = new System.Drawing.Point(26, 136);
          this.txbPop3Port.Name = "txbPop3Port";
          this.txbPop3Port.Size = new System.Drawing.Size(240, 20);
          this.txbPop3Port.TabIndex = 7;
          this.txbPop3Port.Text = "110";
          // 
          // lblPop3Port
          // 
          this.lblPop3Port.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
            | System.Windows.Forms.AnchorStyles.Right)));
          this.lblPop3Port.Location = new System.Drawing.Point(26, 104);
          this.lblPop3Port.Name = "lblPop3Port";
          this.lblPop3Port.Size = new System.Drawing.Size(240, 23);
          this.lblPop3Port.TabIndex = 6;
          this.lblPop3Port.Text = "Укажите почтовый порт:";
          this.lblPop3Port.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
          // 
          // btnNext
          // 
          this.btnNext.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
          this.btnNext.Location = new System.Drawing.Point(192, 200);
          this.btnNext.Name = "btnNext";
          this.btnNext.TabIndex = 9;
          this.btnNext.Text = "Далее";
          this.btnNext.Click += new System.EventHandler(this.btnNext_Click);
          // 
          // CUWStep2
          // 
          this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
          this.ClientSize = new System.Drawing.Size(292, 238);
          this.Controls.Add(this.btnNext);
          this.Controls.Add(this.lblPop3PortSample);
          this.Controls.Add(this.txbPop3Port);
          this.Controls.Add(this.lblPop3Port);
          this.Controls.Add(this.lblPop3Sample);
          this.Controls.Add(this.txbPop3);
          this.Controls.Add(this.lblPop3);
          this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
          this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
          this.Name = "CUWStep2";
          this.Text = "Шаг 2 из 3";
          this.WindowState = System.Windows.Forms.FormWindowState.Maximized;
          this.ResumeLayout(false);
    
        }
        #endregion
    
        private void btnNext_Click(object sender, System.EventArgs e)
        {
          if(txbPop3.Text == "")
          {
            MessageBox.Show("Введите адрес сервера POP3");
          }
          else
          {
            this.identity.Pop3 = txbPop3.Text;
            try
            {
              //Преобразовываем введенное значение в тип Int32 
              this.identity.Pop3Port = Int32.Parse(txbPop3Port.Text);
              CUWStep3 step3 = new CUWStep3(this.identity);
              step3.MdiParent = this.MdiParent;
              this.Close();
              step3.Show();
            }
            catch(Exception)
            {
              MessageBox.Show("Значение порта должно быть числом");
            }
          }
    
        }
      }
    }

    Третий шаг Мастера. Форма CUWStep3.cs

    Значения свойства Name элементов управления этой формы приведены на рис. 3.29.

    (рис 3.29) Форма CUWStep3

    Полный листинг формы:

    using System;
    using System.Drawing;
    using System.Collections;
    using System.ComponentModel;
    using System.Windows.Forms;
    using System.Threading;
    using System.Security.Principal;
    
    namespace MailApplication
    {
      /// <summary>
      /// Summary description for CUWStep3.
      /// </summary>
      public class CUWStep3 : System.Windows.Forms.Form
      {
        private UserIdentity identity;
        private System.Windows.Forms.Label lblSmtpSample;
        private System.Windows.Forms.TextBox txbSmtp;
        private System.Windows.Forms.Label lblSmtp;
        private System.Windows.Forms.Button btnFinish;
        /// <summary>
        /// Required designer variable.
        /// </summary>
        private System.ComponentModel.Container components = null;
    
        public CUWStep3(UserIdentity identity)
        {
          InitializeComponent();
          this.identity = identity;
        }
    
        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        protected override void Dispose( bool disposing )
        {
          if( disposing )
          {
            if(components != null)
            {
              components.Dispose();
            }
          }
          base.Dispose( disposing );
        }
    
        #region Windows Form Designer generated code
        /// <summary>
        /// Required method for Designer support — do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
          System.Resources.ResourceManager resources = new System.Resources.ResourceManager(typeof(CUWStep3));
          this.lblSmtpSample = new System.Windows.Forms.Label();
          this.txbSmtp = new System.Windows.Forms.TextBox();
          this.lblSmtp = new System.Windows.Forms.Label();
          this.btnFinish = new System.Windows.Forms.Button();
          this.SuspendLayout();
          // 
          // lblSmtpSample
          // 
          this.lblSmtpSample.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
            | System.Windows.Forms.AnchorStyles.Right)));
          this.lblSmtpSample.ForeColor = System.Drawing.SystemColors.AppWorkspace;
          this.lblSmtpSample.Location = new System.Drawing.Point(26, 72);
          this.lblSmtpSample.Name = "lblSmtpSample";
          this.lblSmtpSample.Size = new System.Drawing.Size(240, 23);
          this.lblSmtpSample.TabIndex = 8;
          this.lblSmtpSample.Text = "Например, smtp.mail.com";
          this.lblSmtpSample.TextAlign = System.Drawing.ContentAlignment.TopRight;
          // 
          // txbSmtp
          // 
          this.txbSmtp.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
            | System.Windows.Forms.AnchorStyles.Right)));
          this.txbSmtp.Location = new System.Drawing.Point(26, 48);
          this.txbSmtp.Name = "txbSmtp";
          this.txbSmtp.Size = new System.Drawing.Size(240, 20);
          this.txbSmtp.TabIndex = 7;
          this.txbSmtp.Text = "";
          // 
          // lblSmtp
          // 
          this.lblSmtp.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
            | System.Windows.Forms.AnchorStyles.Right)));
          this.lblSmtp.Location = new System.Drawing.Point(26, 16);
          this.lblSmtp.Name = "lblSmtp";
          this.lblSmtp.Size = new System.Drawing.Size(240, 23);
          this.lblSmtp.TabIndex = 6;
          this.lblSmtp.Text = "Введите адрес SMTP-сервера:";
          this.lblSmtp.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
          // 
          // btnFinish
          // 
          this.btnFinish.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
          this.btnFinish.Location = new System.Drawing.Point(200, 208);
          this.btnFinish.Name = "btnFinish";
          this.btnFinish.TabIndex = 9;
          this.btnFinish.Text = "Готово";
          this.btnFinish.Click += new System.EventHandler(this.btnFinish_Click);
          // 
          // CUWStep3
          // 
          this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
          this.ClientSize = new System.Drawing.Size(292, 266);
          this.Controls.Add(this.btnFinish);
          this.Controls.Add(this.lblSmtpSample);
          this.Controls.Add(this.txbSmtp);
          this.Controls.Add(this.lblSmtp);
          this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
          this.Name = "CUWStep3";
          this.Text = "Шаг 3 из 3";
          this.WindowState = System.Windows.Forms.FormWindowState.Maximized;
          this.ResumeLayout(false);
    
        }
        #endregion
    
        private void btnFinish_Click(object sender, System.EventArgs e)
        {
          if(txbSmtp.Text != "")
          {
            this.identity.Smtp = txbSmtp.Text;
            //Закрываем текущую форму
            this.Close();
            Thread.CurrentPrincipal = new GenericPrincipal(this.identity, new string[]{"user"});
            this.identity.Dispose();
            //Закрываем родительскую форму CreateUserWizard  
            Form.ActiveForm.Close();
            
          }
          else
          {
            MessageBox.Show("Введите адрес сервера SMTP");
          }
        }
    
      
      }
    }

    Главная форма mainForm.cs

    Главная форма программы представляет собой контейнер для других форм и поэтому содержит сравнительно мало элементов управления. Значения свойства Name элементов управления приведены на рис. 3.30.

    (рис 3.30) Форма mainForm

    Полный листинг формы:

    using System;
    using System.Drawing;
    using System.Collections;
    using System.ComponentModel;
    using System.Windows.Forms;
    using System.Data;
    using System.Threading;
    using System.Security.Principal;
    
    namespace MailApplication
    {
      /// <summary>
      /// Summary description for Form1.
      /// </summary>
      public class mainForm : System.Windows.Forms.Form
      {
        private System.Windows.Forms.MainMenu mainMenu;
        private System.Windows.Forms.MenuItem itemFile;
        private System.Windows.Forms.MenuItem itemUsers;
        private System.Windows.Forms.MenuItem itemNewUser;
        private System.Windows.Forms.MenuItem itemExit;
        private System.Windows.Forms.MenuItem itemEvent;
        private System.Windows.Forms.MenuItem itemGet;
        private System.Windows.Forms.MenuItem itemSend;
        private System.Windows.Forms.MenuItem itemSetting;
        /// <summary>
        /// Required designer variable.
        /// </summary>
        private System.ComponentModel.Container components = null;
    
        public mainForm()
        {
          //
          // Required for Windows Form Designer support
          //
          InitializeComponent();
    
          //
          // TODO: Add any constructor code after InitializeComponent call
          //
        }
    
        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        protected override void Dispose( bool disposing )
        {
          if( disposing )
          {
            if (components != null) 
            {
              components.Dispose();
            }
          }
          base.Dispose( disposing );
        }
    
        #region Windows Form Designer generated code
        /// <summary>
        /// Required method for Designer support — do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
          System.Resources.ResourceManager resources = new System.Resources.ResourceManager(typeof(mainForm));
          this.mainMenu = new System.Windows.Forms.MainMenu();
          this.itemFile = new System.Windows.Forms.MenuItem();
          this.itemNewUser = new System.Windows.Forms.MenuItem();
          this.itemUsers = new System.Windows.Forms.MenuItem();
          this.itemExit = new System.Windows.Forms.MenuItem();
          this.itemEvent = new System.Windows.Forms.MenuItem();
          this.itemGet = new System.Windows.Forms.MenuItem();
          this.itemSend = new System.Windows.Forms.MenuItem();
          this.itemSetting = new System.Windows.Forms.MenuItem();
          // 
          // mainMenu
          // 
          this.mainMenu.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] {
                                               this.itemFile,
                                               this.itemEvent});
          // 
          // itemFile
          // 
          this.itemFile.Index = 0;
          this.itemFile.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] {
                                               this.itemNewUser,
                                               this.itemUsers,
                                               this.itemExit});
          this.itemFile.Text = "Файл";
          // 
          // itemNewUser
          // 
          this.itemNewUser.Index = 0;
          this.itemNewUser.Shortcut = System.Windows.Forms.Shortcut.CtrlN;
          this.itemNewUser.Text = "Новый пользователь";
          this.itemNewUser.Click += new System.EventHandler(this.itemNewUser_Click);
          // 
          // itemUsers
          // 
          this.itemUsers.Index = 1;
          this.itemUsers.Shortcut = System.Windows.Forms.Shortcut.CtrlL;
          this.itemUsers.Text = "Смена пользователя";
          this.itemUsers.Click += new System.EventHandler(this.itemUsers_Click);
          // 
          // itemExit
          // 
          this.itemExit.Index = 2;
          this.itemExit.Shortcut = System.Windows.Forms.Shortcut.AltF4;
          this.itemExit.Text = "Выход";
          this.itemExit.Click += new System.EventHandler(this.itemExit_Click);
          // 
          // itemEvent
          // 
          this.itemEvent.Enabled = false;
          this.itemEvent.Index = 1;
          this.itemEvent.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] {
                                                this.itemGet,
                                                this.itemSend,
                                                this.itemSetting});
          this.itemEvent.Text = "Действия";
          // 
          // itemGet
          // 
          this.itemGet.Index = 0;
          this.itemGet.Shortcut = System.Windows.Forms.Shortcut.CtrlG;
          this.itemGet.Text = "Получить почту";
          this.itemGet.Click += new System.EventHandler(this.itemGet_Click);
          // 
          // itemSend
          // 
          this.itemSend.Index = 1;
          this.itemSend.Shortcut = System.Windows.Forms.Shortcut.CtrlS;
          this.itemSend.Text = "Отправить письмо";
          this.itemSend.Click += new System.EventHandler(this.itemSend_Click);
          // 
          // itemSetting
          // 
          this.itemSetting.Index = 2;
          this.itemSetting.Shortcut = System.Windows.Forms.Shortcut.CtrlO;
          this.itemSetting.Text = "Настройки";
          this.itemSetting.Visible = false;
          // 
          // mainForm
          // 
          this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
          this.ClientSize = new System.Drawing.Size(792, 545);
          this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
          this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
          this.IsMdiContainer = true;
          this.Menu = this.mainMenu;
          this.Name = "mainForm";
          this.Text = "Ballet";
          this.Closing += new System.ComponentModel.CancelEventHandler(this.mainForm_Closing);
          this.Load += new System.EventHandler(this.itemUsers_Click);
    
        }
        #endregion
    
        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        [STAThread]
        static void Main() 
        {
          Application.Run(new mainForm());
        }
    
        private void itemExit_Click(object sender, System.EventArgs e)
        {
          this.Close();
        }
    
        private void itemUsers_Click(object sender, System.EventArgs e)
        {
          selectUser select = new selectUser();
          if(select.ShowDialog() != DialogResult.OK)
            //Запускаем главную форму.
            return;
          if(Thread.CurrentPrincipal.Identity is UserIdentity)
            ((UserIdentity)Thread.CurrentPrincipal.Identity).Dispose();
          string userName = select.lstViewUsers.SelectedItems[0].Text;      
          UserIdentity identity = new UserIdentity(userName);      
          Thread.CurrentPrincipal = new GenericPrincipal(identity, new string[]{"user"});
          //Вызываем метод ActivateEventItem
          this.ActivateEventItem();
        }
    
        private void ActivateEventItem()
        {
          //Включаем доступность пункта меню "Действия".
          this.itemEvent.Enabled = true;
        }
    
        private void itemNewUser_Click(object sender, System.EventArgs e)
        {
          //Создаем экземпляр wizard формы CreateUserWizard
          CreateUserWizard wizard = new CreateUserWizard();
          //Показываем форму:
          wizard.ShowDialog();
          if(Thread.CurrentPrincipal != null)
            this.ActivateEventItem();
        }
    
        private void mainForm_Closing(object sender, System.ComponentModel.CancelEventArgs e)
        {
          if(Thread.CurrentPrincipal.Identity is UserIdentity)
            ((UserIdentity)Thread.CurrentPrincipal.Identity).Dispose();
        }
    
        private void itemSend_Click(object sender, System.EventArgs e)
        {      
          PasswordPromt pass = new PasswordPromt();
          if(pass.ShowDialog() != DialogResult.OK)
            return;
          SendMessage send = new SendMessage();
          send.MdiParent = this;
          send.Show();
        }
    
        private void itemGet_Click(object sender, System.EventArgs e)
        {
          PasswordPromt pass = new PasswordPromt();
          if(pass.ShowDialog() != DialogResult.OK)
            return;
          MessageList list = new MessageList();
          list.MdiParent = this;
          list.Show();
        }
    
        
    
        
      }
    }

    Форма списка сообщений MessageList.cs

    Значения свойства Name элементов управления этой формы приведены на рис. 3.31.

    (рис 3.31) Форма MessageList

    Полный листинг формы:

    using System;
    using System.Drawing;
    using System.Collections;
    using System.ComponentModel;
    using System.Windows.Forms;
    
    namespace MailApplication
    {
      /// <summary>
      /// Summary description for MessageList.
      /// </summary>
      public class MessageList : System.Windows.Forms.Form
      {
        private Mail.Providers.Pop3 mail;
        private UserIdentity identity;
        private System.Windows.Forms.ListView lstViewMessages;
        private System.Windows.Forms.ColumnHeader colFrom;
        private System.Windows.Forms.ColumnHeader colSubject;
        private System.Windows.Forms.ColumnHeader colDate;
        private System.Windows.Forms.ImageList imageListIcons;
        private System.Windows.Forms.ColumnHeader colIcon;
        private System.Windows.Forms.Label lblMessagesCount;
        private System.Windows.Forms.Panel pnlPages;
        private System.ComponentModel.IContainer components;
    
        public MessageList()
        {
          InitializeComponent();
          
          identity = (UserIdentity)System.Threading.Thread.CurrentPrincipal.Identity;
          // Создание объекта POP3. 
          if(identity.Pop3Port == -1)
            mail = new Mail.Providers.Pop3(identity.Pop3);
          else
            mail = new Mail.Providers.Pop3(identity.Pop3, identity.Pop3Port);
        }
    
        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        protected override void Dispose( bool disposing )
        {
          if( disposing )
          {
            if(components != null)
            {
              components.Dispose();
            }
          }
          base.Dispose( disposing );
        }
    
        #region Windows Form Designer generated code
        /// <summary>
        /// Required method for Designer support — do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
          this.components = new System.ComponentModel.Container();
          System.Resources.ResourceManager resources = new System.Resources.ResourceManager(typeof(MessageList));
          this.lstViewMessages = new System.Windows.Forms.ListView();
          this.colFrom = new System.Windows.Forms.ColumnHeader();
          this.colSubject = new System.Windows.Forms.ColumnHeader();
          this.colDate = new System.Windows.Forms.ColumnHeader();
          this.imageListIcons = new System.Windows.Forms.ImageList(this.components);
          this.colIcon = new System.Windows.Forms.ColumnHeader();
          this.lblMessagesCount = new System.Windows.Forms.Label();
          this.pnlPages = new System.Windows.Forms.Panel();
          this.SuspendLayout();
          // 
          // lstViewMessages
          // 
          this.lstViewMessages.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
            | System.Windows.Forms.AnchorStyles.Right)));
          this.lstViewMessages.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] {
                                                    this.colIcon,
                                                    this.colFrom,
                                                    this.colSubject,
                                                    this.colDate});
          this.lstViewMessages.Cursor = System.Windows.Forms.Cursors.Hand;
          this.lstViewMessages.FullRowSelect = true;
          this.lstViewMessages.GridLines = true;
          this.lstViewMessages.Location = new System.Drawing.Point(16, 40);
          this.lstViewMessages.MultiSelect = false;
          this.lstViewMessages.Name = "lstViewMessages";
          this.lstViewMessages.Size = new System.Drawing.Size(632, 352);
          this.lstViewMessages.SmallImageList = this.imageListIcons;
          this.lstViewMessages.TabIndex = 0;
          this.lstViewMessages.View = System.Windows.Forms.View.Details;
          this.lstViewMessages.Click += new System.EventHandler(this.lstViewMessages_Click);
          // 
          // colFrom
          // 
          this.colFrom.Text = "От";
          this.colFrom.Width = 177;
          // 
          // colSubject
          // 
          this.colSubject.Text = "Тема";
          this.colSubject.Width = 306;
          // 
          // colDate
          // 
          this.colDate.Text = "Дата";
          this.colDate.Width = 106;
          // 
          // imageListIcons
          // 
          this.imageListIcons.ImageSize = new System.Drawing.Size(16, 16);
          this.imageListIcons.ImageStream = ((System.Windows.Forms.ImageListStreamer)(resources.GetObject("imageListIcons.ImageStream")));
          this.imageListIcons.TransparentColor = System.Drawing.Color.Transparent;
          // 
          // colIcon
          // 
          this.colIcon.Text = "#";
          this.colIcon.Width = 39;
          // 
          // lblMessagesCount
          // 
          this.lblMessagesCount.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
            | System.Windows.Forms.AnchorStyles.Right)));
          this.lblMessagesCount.Location = new System.Drawing.Point(16, 8);
          this.lblMessagesCount.Name = "lblMessagesCount";
          this.lblMessagesCount.Size = new System.Drawing.Size(456, 23);
          this.lblMessagesCount.TabIndex = 1;
          this.lblMessagesCount.Text = "Писем в почтовом ящике: ";
          this.lblMessagesCount.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
          // 
          // pnlPages
          // 
          this.pnlPages.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left) 
            | System.Windows.Forms.AnchorStyles.Right)));
          this.pnlPages.Location = new System.Drawing.Point(16, 400);
          this.pnlPages.Name = "pnlPages";
          this.pnlPages.Size = new System.Drawing.Size(632, 32);
          this.pnlPages.TabIndex = 2;
          // 
          // MessageList
          // 
          this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
          this.ClientSize = new System.Drawing.Size(664, 438);
          this.Controls.Add(this.pnlPages);
          this.Controls.Add(this.lblMessagesCount);
          this.Controls.Add(this.lstViewMessages);
          this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
          this.Name = "MessageList";
          this.Text = "Список сообщений";
          this.WindowState = System.Windows.Forms.FormWindowState.Maximized;
          this.Load += new System.EventHandler(this.MessageList_Load);
          this.ResumeLayout(false);
    
        }
        #endregion
        
        private void MessageList_Load(object sender, System.EventArgs e)
        {
          try
          {  
            // Вход в почтовый сервер.
            mail.LogIn(identity.Name, identity.Password);
            // Отображение количества сообщений.
            lblMessagesCount.Text += mail.NumberOfMessages.ToString();
            this.LoadCurrentPageMessages(1);
            this.DrawPages(1);
          }
          catch(Exception ex)
          {
            MessageBox.Show("При выполнении подключения возникла ошибка: " + ex.Message);
          }      
        }
        /// <summary>
        /// Прорисовывает листинг страниц.
        /// </summary>
        /// <param name="currentPageIndex">Номер текущей страницы.</param>
        void DrawPages(uint currentPageIndex)
        {
          // Очищаем контейнер.
          pnlPages.Controls.Clear();
          uint messagesPerPage = 20;
          uint pagesCount = (uint)(mail.NumberOfMessages / messagesPerPage);      
          // Отображаем номера существующих страниц.
          for(uint i = 1; i <= pagesCount; i++)
          {
            LinkLabel page = new LinkLabel();
            page.Text = i.ToString();
            page.Tag = i;
            page.Click += new EventHandler(page_Click);
            if(i == currentPageIndex)
              page.ForeColor = Color.Black;
            page.Size = new Size(20, 20);
            page.Location = new Point(30 * (int)i, 5);
            pnlPages.Controls.Add(page);
          }
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void page_Click(object sender, EventArgs e)
        {
          uint newPageIndex = Convert.ToUInt32(((LinkLabel)sender).Tag);
          this.LoadCurrentPageMessages(newPageIndex);
          this.DrawPages(newPageIndex);
        }
    
        /// <summary>
        /// Отображает сообщения текущей страницы.
        /// </summary>
        /// <param name="currentPageIndex">Номер текущей страницы.</param>
        void LoadCurrentPageMessages(uint currentPageIndex)
        {
          // Количество сообщений на странице.
          uint messagesPerPage = 20;
          // Индекс первого сообщения на странице.
          uint startIndex = mail.NumberOfMessages — messagesPerPage * currentPageIndex;
          // Индекс последнего сообщения на странице.
          uint finishIndex = startIndex + 20;
          // Загрузка заголовков сообщений.
          for(uint currentMessageIndex = startIndex + 1;
            currentMessageIndex <= finishIndex; currentMessageIndex++)
          {
            Mail.Message msg = null;        
            try
            {
              // Попытка загрузки заголовков сообщения.
              msg = mail.GetMessageHeader(currentMessageIndex, 0);
            }
            catch(Exception ex)
            {
              // Отображение возникшей ошибки.
              MessageBox.Show("При загрузке заголовков сообщения возникла ошибка. Номер сообщения: " +
                currentMessageIndex + "; Текст ошибки: " + ex.Message);
            }
            // Если возникла ошибка, то пропускаем текущее сообщение.
            if(msg == null)
              continue;
            // Отображение информации о сообщении.
            ListViewItem item = new ListViewItem(
              new string[]{currentMessageIndex.ToString(), msg.FromEmail, msg.Subject, msg.Date},
              0);
            item.Tag = currentMessageIndex;
            lstViewMessages.Items.Add(item);
          }
        }
    
    
        private void lstViewMessages_Click(object sender, System.EventArgs e)
        {
          try
          {
            // Получение номера выделенного сообщения.
            uint messageIndex = Convert.ToUInt32(lstViewMessages.SelectedItems[0].Tag);
            // Загрузка сообщения с сервера.
            Mail.Message msg = mail.GetMessage(messageIndex);
            // Отображение сообщения.
            ViewMessage messageViewer = new ViewMessage(msg);
            messageViewer.ShowDialog();
          }
          catch(Exception ex)
          {
            MessageBox.Show("Во время загрузки сообщения произошла следующая ошибка: " + ex.Message);
          }
        }
    
      }
    }

    Форма ввода пароля PasswordPromt.cs

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

    (рис 3.32) Форма PasswordPromt.

    Полный листинг формы:

    using System;
    using System.Drawing;
    using System.Collections;
    using System.ComponentModel;
    using System.Windows.Forms;
    
    namespace MailApplication
    {
      /// <summary>
      /// Summary description for PasswordPromt.
      /// </summary>
      public class PasswordPromt : System.Windows.Forms.Form
      {
        private System.Windows.Forms.Label lblPassword;
        private System.Windows.Forms.TextBox txbPassword;
        private System.Windows.Forms.Button btnSubmit;
        /// <summary>
        /// Required designer variable.
        /// </summary>
        private System.ComponentModel.Container components = null;
    
        public PasswordPromt()
        {
          //
          // Required for Windows Form Designer support
          //
          InitializeComponent();
    
          //
          // TODO: Add any constructor code after InitializeComponent call
          //
        }
    
        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        protected override void Dispose( bool disposing )
        {
          if( disposing )
          {
            if(components != null)
            {
              components.Dispose();
            }
          }
          base.Dispose( disposing );
        }
    
        #region Windows Form Designer generated code
        /// <summary>
        /// Required method for Designer support — do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
          System.Resources.ResourceManager resources = new System.Resources.ResourceManager(typeof(PasswordPromt));
          this.lblPassword = new System.Windows.Forms.Label();
          this.txbPassword = new System.Windows.Forms.TextBox();
          this.btnSubmit = new System.Windows.Forms.Button();
          this.SuspendLayout();
          // 
          // lblPassword
          // 
          this.lblPassword.Location = new System.Drawing.Point(16, 8);
          this.lblPassword.Name = "lblPassword";
          this.lblPassword.Size = new System.Drawing.Size(296, 23);
          this.lblPassword.TabIndex = 0;
          this.lblPassword.Text = "Введите пароль от почтового ящика";
          this.lblPassword.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
          // 
          // txbPassword
          // 
          this.txbPassword.Location = new System.Drawing.Point(16, 40);
          this.txbPassword.Name = "txbPassword";
          this.txbPassword.PasswordChar = '*';
          this.txbPassword.Size = new System.Drawing.Size(296, 20);
          this.txbPassword.TabIndex = 1;
          this.txbPassword.Text = "";
          // 
          // btnSubmit
          // 
          this.btnSubmit.Location = new System.Drawing.Point(240, 72);
          this.btnSubmit.Name = "btnSubmit";
          this.btnSubmit.TabIndex = 2;
          this.btnSubmit.Text = "ОК";
          this.btnSubmit.Click += new System.EventHandler(this.btnSubmit_Click);
          // 
          // PasswordPromt
          // 
          this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
          this.ClientSize = new System.Drawing.Size(328, 110);
          this.Controls.Add(this.btnSubmit);
          this.Controls.Add(this.txbPassword);
          this.Controls.Add(this.lblPassword);
          this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedToolWindow;
          this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
          this.MaximizeBox = false;
          this.MinimizeBox = false;
          this.Name = "PasswordPromt";
          this.Text = "Запрос пароля";
          this.ResumeLayout(false);
        }
        #endregion
    
        private void btnSubmit_Click(object sender, System.EventArgs e)
        {
          if(txbPassword.Text == "")
          {
            MessageBox.Show("Пароль не может быть пустым");
          }
          else
          {
            this.DialogResult = DialogResult.OK;
            ((UserIdentity)System.Threading.Thread.CurrentPrincipal.Identity).Password = txbPassword.Text;
            this.Close();
          }
        }
      }
    }

    Форма выбора пользователя selectUser.cs

    Форма выбора пользователя появляется при запуске программы, она также используется для смены пользователя. Значения свойства Name элементов управления этой формы приведены на рис. 3.33:

    (рис 3.33) Форма selectUser

    Полный листинг формы:

    using System;
    using System.Drawing;
    using System.Collections;
    using System.ComponentModel;
    using System.Windows.Forms;
    using System.IO;
    
    namespace MailApplication
    {
      /// <summary>
      /// Summary description for selectUser.
      /// </summary>
      public class selectUser : System.Windows.Forms.Form
      {
        public System.Windows.Forms.ListView lstViewUsers;
        private System.Windows.Forms.Button btnCancel;
        private System.Windows.Forms.Button btnSelect;
        private System.Windows.Forms.Label lblUserSelect;
        private System.Windows.Forms.ImageList imgLstUser;
        private System.Windows.Forms.ColumnHeader colUserName;
        private System.ComponentModel.IContainer components;
    
        public selectUser()
        {
          //
          // Required for Windows Form Designer support
          //
          InitializeComponent();
    
          //
          // TODO: Add any constructor code after InitializeComponent call
          //
        }
    
        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        protected override void Dispose( bool disposing )
        {
          if( disposing )
          {
            if(components != null)
            {
              components.Dispose();
            }
          }
          base.Dispose( disposing );
        }
    
        #region Windows Form Designer generated code
        /// <summary>
        /// Required method for Designer support — do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
          this.components = new System.ComponentModel.Container();
          System.Resources.ResourceManager resources = new System.Resources.ResourceManager(typeof(selectUser));
          this.lstViewUsers = new System.Windows.Forms.ListView();
          this.colUserName = new System.Windows.Forms.ColumnHeader();
          this.imgLstUser = new System.Windows.Forms.ImageList(this.components);
          this.btnCancel = new System.Windows.Forms.Button();
          this.btnSelect = new System.Windows.Forms.Button();
          this.lblUserSelect = new System.Windows.Forms.Label();
          this.SuspendLayout();
          // 
          // lstViewUsers
          // 
          this.lstViewUsers.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] {
                                                   this.colUserName});
          this.lstViewUsers.Cursor = System.Windows.Forms.Cursors.Hand;
          this.lstViewUsers.GridLines = true;
          this.lstViewUsers.Location = new System.Drawing.Point(8, 40);
          this.lstViewUsers.MultiSelect = false;
          this.lstViewUsers.Name = "lstViewUsers";
          this.lstViewUsers.Size = new System.Drawing.Size(272, 176);
          this.lstViewUsers.SmallImageList = this.imgLstUser;
          this.lstViewUsers.TabIndex = 0;
          this.lstViewUsers.View = System.Windows.Forms.View.Details;
          // 
          // colUserName
          // 
          this.colUserName.Text = "Имя пользователя";
          this.colUserName.Width = 268;
          // 
          // imgLstUser
          // 
          this.imgLstUser.ImageSize = new System.Drawing.Size(16, 16);
          this.imgLstUser.ImageStream = ((System.Windows.Forms.ImageListStreamer)(resources.GetObject("imgLstUser.ImageStream")));
          this.imgLstUser.TransparentColor = System.Drawing.Color.Transparent;
          // 
          // btnCancel
          // 
          this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel;
          this.btnCancel.Location = new System.Drawing.Point(200, 232);
          this.btnCancel.Name = "btnCancel";
          this.btnCancel.TabIndex = 1;
          this.btnCancel.Text = "Отмена";
          this.btnCancel.Click += new System.EventHandler(this.btnCancel_Click);
          // 
          // btnSelect
          // 
          this.btnSelect.Location = new System.Drawing.Point(128, 232);
          this.btnSelect.Name = "btnSelect";
          this.btnSelect.TabIndex = 2;
          this.btnSelect.Text = "Выбор";
          this.btnSelect.Click += new System.EventHandler(this.btnSelect_Click);
          // 
          // lblUserSelect
          // 
          this.lblUserSelect.Location = new System.Drawing.Point(8, 8);
          this.lblUserSelect.Name = "lblUserSelect";
          this.lblUserSelect.Size = new System.Drawing.Size(272, 23);
          this.lblUserSelect.TabIndex = 3;
          this.lblUserSelect.Text = "Выберите пользователя из списка:";
          this.lblUserSelect.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
          // 
          // selectUser
          // 
          this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
          this.CancelButton = this.btnCancel;
          this.ClientSize = new System.Drawing.Size(292, 266);
          this.Controls.Add(this.lblUserSelect);
          this.Controls.Add(this.btnSelect);
          this.Controls.Add(this.btnCancel);
          this.Controls.Add(this.lstViewUsers);
          this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
          this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
          this.Name = "selectUser";
          this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
          this.Text = "Выбор пользователя";
          this.Load += new System.EventHandler(this.selectUser_Load);
          this.ResumeLayout(false);
    
        }
        #endregion
    
        private void selectUser_Load(object sender, System.EventArgs e)
        {
          DirectoryInfo dir = new DirectoryInfo(Environment.CurrentDirectory);
          FileInfo[] users = dir.GetFiles("*.usr");      
          foreach(FileInfo user in users)
          {
            ListViewItem item = new ListViewItem(user.Name, 0);
            lstViewUsers.Items.Add(item);
          }
        }
    
        private void btnSelect_Click(object sender, System.EventArgs e)
        {
          if(lstViewUsers.SelectedItems.Count == 0)
            MessageBox.Show("Выберите пользователя для начала работы", "Пользователь не выбран");
          else
          {
            this.DialogResult = DialogResult.OK;
            this.Close();
          }
        }
    
        private void btnCancel_Click(object sender, System.EventArgs e)
        {
          this.Close();
        }
      }
    }

    Форма отправки сообщений SendMessage.cs

    На этой форме подготавливается сообщение к отправке. Значения свойства Name элементов управления приведены на рис. 3.34.

    (рис 3.34) Форма SendMessage

    Полный листинг формы:

    using System;
    using System.Drawing;
    using System.Collections;
    using System.ComponentModel;
    using System.Windows.Forms;
    using System.Web.Mail;
    using System.Threading;
    
    namespace MailApplication
    {
      /// <summary>
      /// Summary description for SendMessage.
      /// </summary>
      public class SendMessage : System.Windows.Forms.Form
      {
        private MailMessage message;
        private System.Windows.Forms.Label lblTo;
        private System.Windows.Forms.TextBox txbTo;
        private System.Windows.Forms.TextBox txbCopy;
        private System.Windows.Forms.Label lblCopy;
        private System.Windows.Forms.TextBox txbBlindCopy;
        private System.Windows.Forms.Label lblBlindCopy;
        private System.Windows.Forms.TextBox txbSubject;
        private System.Windows.Forms.Label lblSubject;
        private System.Windows.Forms.TextBox txbBody;
        private System.Windows.Forms.Label lblBody;
        private System.Windows.Forms.Button btnSend;
        private System.Windows.Forms.Panel pblAttachments;
        private System.Windows.Forms.Label lblAttachments;
        private System.Windows.Forms.Button btnAddAttach;
        private System.Windows.Forms.Button btnViewAttach;
        private System.Windows.Forms.TextBox txbAttach;
        private System.Windows.Forms.Label lblAttachNumber;
        private System.Windows.Forms.OpenFileDialog oFDAttach;
        private System.Windows.Forms.ContextMenu contextMenuDeleteAttach;
        private System.Windows.Forms.MenuItem itemDeleteAttach;
        /// <summary>
        /// Required designer variable.
        /// </summary>
        private System.ComponentModel.Container components = null;
    
        public SendMessage()
        {
          InitializeComponent();
          message = new MailMessage();
        }
    
        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        protected override void Dispose( bool disposing )
        {
          if( disposing )
          {
            if(components != null)
            {
              components.Dispose();
            }
          }
          base.Dispose( disposing );
        }
    
        #region Windows Form Designer generated code
        /// <summary>
        /// Required method for Designer support — do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
          System.Resources.ResourceManager resources = new System.Resources.ResourceManager(typeof(SendMessage));
          this.lblTo = new System.Windows.Forms.Label();
          this.txbTo = new System.Windows.Forms.TextBox();
          this.txbCopy = new System.Windows.Forms.TextBox();
          this.lblCopy = new System.Windows.Forms.Label();
          this.txbBlindCopy = new System.Windows.Forms.TextBox();
          this.lblBlindCopy = new System.Windows.Forms.Label();
          this.txbSubject = new System.Windows.Forms.TextBox();
          this.lblSubject = new System.Windows.Forms.Label();
          this.txbBody = new System.Windows.Forms.TextBox();
          this.lblBody = new System.Windows.Forms.Label();
          this.btnSend = new System.Windows.Forms.Button();
          this.pblAttachments = new System.Windows.Forms.Panel();
          this.lblAttachments = new System.Windows.Forms.Label();
          this.btnAddAttach = new System.Windows.Forms.Button();
          this.btnViewAttach = new System.Windows.Forms.Button();
          this.txbAttach = new System.Windows.Forms.TextBox();
          this.lblAttachNumber = new System.Windows.Forms.Label();
          this.oFDAttach = new System.Windows.Forms.OpenFileDialog();
          this.contextMenuDeleteAttach = new System.Windows.Forms.ContextMenu();
          this.itemDeleteAttach = new System.Windows.Forms.MenuItem();
          this.SuspendLayout();
          // 
          // lblTo
          // 
          this.lblTo.Location = new System.Drawing.Point(32, 16);
          this.lblTo.Name = "lblTo";
          this.lblTo.Size = new System.Drawing.Size(56, 23);
          this.lblTo.TabIndex = 0;
          this.lblTo.Text = "Кому:";
          this.lblTo.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
          // 
          // txbTo
          // 
          this.txbTo.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
            | System.Windows.Forms.AnchorStyles.Right)));
          this.txbTo.Location = new System.Drawing.Point(112, 16);
          this.txbTo.Name = "txbTo";
          this.txbTo.Size = new System.Drawing.Size(560, 20);
          this.txbTo.TabIndex = 1;
          this.txbTo.Text = "";
          // 
          // txbCopy
          // 
          this.txbCopy.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
            | System.Windows.Forms.AnchorStyles.Right)));
          this.txbCopy.Location = new System.Drawing.Point(112, 48);
          this.txbCopy.Name = "txbCopy";
          this.txbCopy.Size = new System.Drawing.Size(560, 20);
          this.txbCopy.TabIndex = 3;
          this.txbCopy.Text = "";
          // 
          // lblCopy
          // 
          this.lblCopy.Location = new System.Drawing.Point(32, 48);
          this.lblCopy.Name = "lblCopy";
          this.lblCopy.Size = new System.Drawing.Size(56, 23);
          this.lblCopy.TabIndex = 2;
          this.lblCopy.Text = "Копия:";
          this.lblCopy.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
          // 
          // txbBlindCopy
          // 
          this.txbBlindCopy.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
            | System.Windows.Forms.AnchorStyles.Right)));
          this.txbBlindCopy.Location = new System.Drawing.Point(112, 80);
          this.txbBlindCopy.Name = "txbBlindCopy";
          this.txbBlindCopy.Size = new System.Drawing.Size(560, 20);
          this.txbBlindCopy.TabIndex = 5;
          this.txbBlindCopy.Text = "";
          // 
          // lblBlindCopy
          // 
          this.lblBlindCopy.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
            | System.Windows.Forms.AnchorStyles.Right)));
          this.lblBlindCopy.Location = new System.Drawing.Point(8, 80);
          this.lblBlindCopy.Name = "lblBlindCopy";
          this.lblBlindCopy.Size = new System.Drawing.Size(88, 23);
          this.lblBlindCopy.TabIndex = 4;
          this.lblBlindCopy.Text = "Скрытая копия:";
          this.lblBlindCopy.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
          // 
          // txbSubject
          // 
          this.txbSubject.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
            | System.Windows.Forms.AnchorStyles.Right)));
          this.txbSubject.Location = new System.Drawing.Point(112, 112);
          this.txbSubject.Name = "txbSubject";
          this.txbSubject.Size = new System.Drawing.Size(560, 20);
          this.txbSubject.TabIndex = 7;
          this.txbSubject.Text = "";
          // 
          // lblSubject
          // 
          this.lblSubject.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
            | System.Windows.Forms.AnchorStyles.Right)));
          this.lblSubject.Location = new System.Drawing.Point(32, 112);
          this.lblSubject.Name = "lblSubject";
          this.lblSubject.Size = new System.Drawing.Size(72, 23);
          this.lblSubject.TabIndex = 6;
          this.lblSubject.Text = "Тема:";
          this.lblSubject.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
          // 
          // txbBody
          // 
          this.txbBody.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
            | System.Windows.Forms.AnchorStyles.Right)));
          this.txbBody.Location = new System.Drawing.Point(16, 168);
          this.txbBody.Multiline = true;
          this.txbBody.Name = "txbBody";
          this.txbBody.Size = new System.Drawing.Size(712, 192);
          this.txbBody.TabIndex = 9;
          this.txbBody.Text = "";
          // 
          // lblBody
          // 
          this.lblBody.Location = new System.Drawing.Point(16, 144);
          this.lblBody.Name = "lblBody";
          this.lblBody.TabIndex = 8;
          this.lblBody.Text = "Текст сообщения:";
          this.lblBody.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
          // 
          // btnSend
          // 
          this.btnSend.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
          this.btnSend.Location = new System.Drawing.Point(648, 440);
          this.btnSend.Name = "btnSend";
          this.btnSend.TabIndex = 10;
          this.btnSend.Text = "Отправить";
          this.btnSend.Click += new System.EventHandler(this.btnSend_Click);
          // 
          // pblAttachments
          // 
          this.pblAttachments.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) 
            | System.Windows.Forms.AnchorStyles.Left) 
            | System.Windows.Forms.AnchorStyles.Right)));
          this.pblAttachments.AutoScroll = true;
          this.pblAttachments.Location = new System.Drawing.Point(16, 416);
          this.pblAttachments.Name = "pblAttachments";
          this.pblAttachments.Size = new System.Drawing.Size(608, 56);
          this.pblAttachments.TabIndex = 12;
          // 
          // lblAttachments
          // 
          this.lblAttachments.Location = new System.Drawing.Point(16, 368);
          this.lblAttachments.Name = "lblAttachments";
          this.lblAttachments.Size = new System.Drawing.Size(64, 23);
          this.lblAttachments.TabIndex = 13;
          this.lblAttachments.Text = "Вложения:";
          this.lblAttachments.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
          // 
          // btnAddAttach
          // 
          this.btnAddAttach.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
          this.btnAddAttach.Location = new System.Drawing.Point(648, 368);
          this.btnAddAttach.Name = "btnAddAttach";
          this.btnAddAttach.TabIndex = 17;
          this.btnAddAttach.Text = "Добавить";
          this.btnAddAttach.Click += new System.EventHandler(this.btnAddAttach_Click);
          // 
          // btnViewAttach
          // 
          this.btnViewAttach.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
          this.btnViewAttach.Location = new System.Drawing.Point(568, 368);
          this.btnViewAttach.Name = "btnViewAttach";
          this.btnViewAttach.TabIndex = 16;
          this.btnViewAttach.Text = "Обзор";
          this.btnViewAttach.Click += new System.EventHandler(this.btnViewAttach_Click);
          // 
          // txbAttach
          // 
          this.txbAttach.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
            | System.Windows.Forms.AnchorStyles.Right)));
          this.txbAttach.Location = new System.Drawing.Point(176, 368);
          this.txbAttach.Name = "txbAttach";
          this.txbAttach.Size = new System.Drawing.Size(384, 20);
          this.txbAttach.TabIndex = 15;
          this.txbAttach.Text = "";
          // 
          // lblAttachNumber
          // 
          this.lblAttachNumber.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
            | System.Windows.Forms.AnchorStyles.Right)));
          this.lblAttachNumber.Location = new System.Drawing.Point(120, 368);
          this.lblAttachNumber.Name = "lblAttachNumber";
          this.lblAttachNumber.Size = new System.Drawing.Size(48, 23);
          this.lblAttachNumber.TabIndex = 14;
          this.lblAttachNumber.Text = "#";
          this.lblAttachNumber.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
          // 
          // oFDAttach
          // 
          this.oFDAttach.Title = "Выбор вложения";
          // 
          // contextMenuDeleteAttach
          // 
          this.contextMenuDeleteAttach.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] {
                                                      this.itemDeleteAttach});
          // 
          // itemDeleteAttach
          // 
          this.itemDeleteAttach.Index = 0;
          this.itemDeleteAttach.Text = "Удалить";
          this.itemDeleteAttach.Click += new System.EventHandler(this.itemDeleteAttach_Click);
          // 
          // SendMessage
          // 
          this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
          this.ClientSize = new System.Drawing.Size(744, 478);
          this.Controls.Add(this.btnAddAttach);
          this.Controls.Add(this.btnViewAttach);
          this.Controls.Add(this.txbAttach);
          this.Controls.Add(this.txbBody);
          this.Controls.Add(this.txbSubject);
          this.Controls.Add(this.txbBlindCopy);
          this.Controls.Add(this.txbCopy);
          this.Controls.Add(this.txbTo);
          this.Controls.Add(this.lblAttachNumber);
          this.Controls.Add(this.lblAttachments);
          this.Controls.Add(this.pblAttachments);
          this.Controls.Add(this.btnSend);
          this.Controls.Add(this.lblBody);
          this.Controls.Add(this.lblSubject);
          this.Controls.Add(this.lblBlindCopy);
          this.Controls.Add(this.lblCopy);
          this.Controls.Add(this.lblTo);
          this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
          this.Name = "SendMessage";
          this.Text = "Отправка сообщения";
          this.WindowState = System.Windows.Forms.FormWindowState.Maximized;
          this.ResumeLayout(false);
    
        }
        #endregion
    
        private void btnViewAttach_Click(object sender, System.EventArgs e)
        {
          if(oFDAttach.ShowDialog() != DialogResult.OK)
            return;
          txbAttach.Text = oFDAttach.FileName;      
        }
    
        private void btnAddAttach_Click(object sender, System.EventArgs e)
        {
          MailAttachment attach = new MailAttachment(oFDAttach.FileName);
          message.Attachments.Add(attach);
          txbAttach.Text = "";
          oFDAttach.FileName = String.Empty;
          this.AddAttachmentsToPanel();
        }
    
        private void AddAttachmentsToPanel()
        {
          pblAttachments.Controls.Clear();
          for(int i = message.Attachments.Count -1; i >= 0; i--)
          {
            MailAttachment attach = (MailAttachment)message.Attachments[i];
            Label lblNumber = new Label();
            Label lblAttachName = new Label();
            lblNumber.Text = String.Format("#{0}", i + 1);
            lblAttachName.Text = attach.Filename;
            lblAttachName.TextAlign = lblNumber.TextAlign = ContentAlignment.MiddleLeft;
            lblAttachName.Anchor = lblNumber.Anchor = AnchorStyles.Top | AnchorStyles.Left;
                    lblNumber.Location = new Point(15, i*25);
            lblAttachName.Location = new Point(50, i*25);
            lblNumber.Size = new Size(20, 20);
            lblAttachName.Size = new Size(500, 20);
            lblNumber.ContextMenu = lblAttachName.ContextMenu = contextMenuDeleteAttach;
            lblNumber.Tag = lblAttachName.Tag = i;
            pblAttachments.Controls.Add(lblNumber);
            pblAttachments.Controls.Add(lblAttachName);
          }
        }
    
        private void itemDeleteAttach_Click(object sender, System.EventArgs e)
        {
          MenuItem item = (MenuItem)sender;
          ContextMenu menu = (ContextMenu)item.Parent;
          Label source = (Label)menu.SourceControl;
          object o = source.Tag;
          int i = Int32.Parse(o.ToString());
          message.Attachments.RemoveAt(i);
          this.AddAttachmentsToPanel();
        }
    
        private void btnSend_Click(object sender, System.EventArgs e)
        {
          message.BodyFormat = MailFormat.Text;
          message.Body = txbBody.Text;
          message.Cc = txbCopy.Text;
          message.Bcc = txbBlindCopy.Text;
          message.Subject = txbSubject.Text;
          message.To = txbTo.Text;
          message.From = ((UserIdentity)Thread.CurrentPrincipal.Identity).Mail;
          Mail.MailSender mailSender = new Mail.MailSender(((UserIdentity)Thread.CurrentPrincipal.Identity).Smtp);
          mailSender.Send(message, ((UserIdentity)Thread.CurrentPrincipal.Identity).Password);
          MessageBox.Show("Ваше сообщение отправлено.");
          this.Close();
        }
      }
    }

    Форма просмотра сообщений ViewMessage.cs

    В эту форму загружается сообщение для чтения при его выборе из списка формы MessageList. Значения свойства Name элементов управления приведены на рис. 3.35.

    (рис 3.35) Форма ViewMessage

    Полный листинг формы:

    using System;
    using System.Drawing;
    using System.Collections;
    using System.ComponentModel;
    using System.Windows.Forms;
    
    namespace MailApplication
    {
      /// <summary>
      /// Summary description for ViewMessage.
      /// </summary>
      public class ViewMessage : System.Windows.Forms.Form
      {
        /// <summary>
        /// Required designer variable.
        /// </summary>    
        private System.ComponentModel.Container components = null;
        
        private System.Windows.Forms.Label lblAttachments;
        private System.Windows.Forms.Panel pblAttachments;
        private System.Windows.Forms.Label lblBody;
        private System.Windows.Forms.Label lblSubject;
        private System.Windows.Forms.Label lblCopy;
        private System.Windows.Forms.Label lblMessageBody;
        private System.Windows.Forms.Label lblFrom;
        private Mail.Message message;
    
        public ViewMessage(Mail.Message msg)
        {
          //
          // Required for Windows Form Designer support
          //
          InitializeComponent();
    
          this.message = msg;
        }
    
        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        protected override void Dispose( bool disposing )
        {
          if( disposing )
          {
            if(components != null)
            {
              components.Dispose();
            }
          }
          base.Dispose( disposing );
        }
    
        #region Windows Form Designer generated code
        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
          System.Resources.ResourceManager resources = new System.Resources.ResourceManager(typeof(ViewMessage));
          this.lblAttachments = new System.Windows.Forms.Label();
          this.pblAttachments = new System.Windows.Forms.Panel();
          this.lblBody = new System.Windows.Forms.Label();
          this.lblSubject = new System.Windows.Forms.Label();
          this.lblCopy = new System.Windows.Forms.Label();
          this.lblFrom = new System.Windows.Forms.Label();
          this.lblMessageBody = new System.Windows.Forms.Label();
          this.SuspendLayout();
          // 
          // lblAttachments
          // 
          this.lblAttachments.Location = new System.Drawing.Point(24, 280);
          this.lblAttachments.Name = "lblAttachments";
          this.lblAttachments.Size = new System.Drawing.Size(64, 23);
          this.lblAttachments.TabIndex = 29;
          this.lblAttachments.Text = "Вложения:";
          this.lblAttachments.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
          // 
          // pblAttachments
          // 
          this.pblAttachments.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) 
            | System.Windows.Forms.AnchorStyles.Left) 
            | System.Windows.Forms.AnchorStyles.Right)));
          this.pblAttachments.AutoScroll = true;
          this.pblAttachments.Location = new System.Drawing.Point(128, 280);
          this.pblAttachments.Name = "pblAttachments";
          this.pblAttachments.Size = new System.Drawing.Size(544, 178);
          this.pblAttachments.TabIndex = 28;
          // 
          // lblBody
          // 
          this.lblBody.Location = new System.Drawing.Point(24, 96);
          this.lblBody.Name = "lblBody";
          this.lblBody.TabIndex = 26;
          this.lblBody.Text = "Текст сообщения:";
          this.lblBody.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
          // 
          // lblSubject
          // 
          this.lblSubject.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
            | System.Windows.Forms.AnchorStyles.Right)));
          this.lblSubject.AutoSize = true;
          this.lblSubject.Location = new System.Drawing.Point(352, 16);
          this.lblSubject.Name = "lblSubject";
          this.lblSubject.Size = new System.Drawing.Size(35, 16);
          this.lblSubject.TabIndex = 24;
          this.lblSubject.Text = "Тема:";
          this.lblSubject.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
          // 
          // lblCopy
          // 
          this.lblCopy.AutoSize = true;
          this.lblCopy.Location = new System.Drawing.Point(24, 56);
          this.lblCopy.Name = "lblCopy";
          this.lblCopy.Size = new System.Drawing.Size(40, 16);
          this.lblCopy.TabIndex = 20;
          this.lblCopy.Text = "Копия:";
          this.lblCopy.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
          // 
          // lblFrom
          // 
          this.lblFrom.AutoSize = true;
          this.lblFrom.Location = new System.Drawing.Point(24, 24);
          this.lblFrom.Name = "lblFrom";
          this.lblFrom.Size = new System.Drawing.Size(47, 16);
          this.lblFrom.TabIndex = 18;
          this.lblFrom.Text = "От кого:";
          this.lblFrom.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
          // 
          // lblMessageBody
          // 
          this.lblMessageBody.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
            | System.Windows.Forms.AnchorStyles.Right)));
          this.lblMessageBody.Location = new System.Drawing.Point(136, 96);
          this.lblMessageBody.Name = "lblMessageBody";
          this.lblMessageBody.Size = new System.Drawing.Size(536, 176);
          this.lblMessageBody.TabIndex = 30;
          // 
          // ViewMessage
          // 
          this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
          this.ClientSize = new System.Drawing.Size(694, 476);
          this.Controls.Add(this.lblMessageBody);
          this.Controls.Add(this.lblAttachments);
          this.Controls.Add(this.pblAttachments);
          this.Controls.Add(this.lblBody);
          this.Controls.Add(this.lblSubject);
          this.Controls.Add(this.lblCopy);
          this.Controls.Add(this.lblFrom);
          this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedToolWindow;
          this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
          this.Name = "ViewMessage";
          this.Text = "Просмотр сообщения";
          this.Load += new System.EventHandler(this.ViewMessage_Load);
          this.ResumeLayout(false);
    
        }
        #endregion
    
        private void ViewMessage_Load(object sender, System.EventArgs e)
        {
          lblMessageBody.Text = this.message.Text;
          lblCopy.Text += this.message.CC;
          lblSubject.Text += this.message.Subject;
          lblFrom.Text += this.message.FromEmail;
        }
    
        private void AddAttachmentsToPanel()
        {
          pblAttachments.Controls.Clear();
          for(int i = message.Attachments.Length -1; i >= 0; i--)
          {
            //MailAttachment attach = (MailAttachment)message.Attachments[i];
            Mail.AttachDescriptor attach = this.message.Attachments[i];
            Label lblNumber = new Label();
            Label lblAttachName = new Label();
            lblNumber.Text = String.Format("#{0}", i + 1);
            lblAttachName.Text = attach.Name;
            lblAttachName.TextAlign = lblNumber.TextAlign = ContentAlignment.MiddleLeft;
            lblAttachName.Anchor = lblNumber.Anchor = AnchorStyles.Top | AnchorStyles.Left;
            lblNumber.Location = new Point(15, i*25);
            lblAttachName.Location = new Point(50, i*25);
            lblNumber.Size = new Size(20, 20);
            lblAttachName.Size = new Size(500, 20);
            //lblNumber.ContextMenu = lblAttachName.ContextMenu = contextMenuDeleteAttach;
            lblNumber.Tag = lblAttachName.Tag = i;
            pblAttachments.Controls.Add(lblNumber);
            pblAttachments.Controls.Add(lblAttachName);
          }
        }
      }
    }
    Вернуться к учебному плану