В этой лекции мы рассмотрим расширенные возможности работы с элементами управления, а также отработаем создание почтовой программы Ballet.
Операция 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).
При размещении на форме элемента управления в режиме дизайна, среда создает код в области Windows Form Designer generated code, описывающий этот элемент. Если мы назначим в обработчике заданного элемента управления генерацию аналогичного кода, то в запущенном приложении можно будет добавлять на форму другие элементы, активизируя этот обработчик. Для добавления элементов управления используется объект ControlsCollection, содержащий ряд методов (см. таблицу 3.1). Под коллекцией элементов понимается их упорядоченная последовательность.
| Метод | Описание |
|---|---|
| Add | Добавление элемента в коллекцию |
| AddRange | Добавление массива элементов |
| Clear | Удаление всех элементов из коллекции |
| Remove | Удаление элемента из коллекции |
| RemoveAt | Удаление элемента по заданному индексу |
| Count | Общее число элементов в коллекции |
Рассмотрим на практике добавление элементов управления. Создайте новое приложение и назовите его RegistrationForm. Располагаем на форме три надписи, два текстовых поля, кнопку, элементы CheckBox и (рис. 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 вставляем скопированный код из обработчика чекбокса. При выборе второго переключателя вся группа элементов, содержащаяся в , будет удалена, а затем в новую группу добавятся два текстовых поля и две надписи:
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).
В зависимости от различных событий, происходящих на форме, содержание контекстного меню может меняться. Создайте новое приложение и назовите его MenuRunTime. Добавляем на форму элемент управления (контейнер) и размещаем внутри него две надписи, текстовое поле, кнопку, ComboBox (выпадающий список) (см. рис. 3.6).
(рис 3.6) Приложение MenuRunTime в режиме дизайнаУстанавливаем следующие свойства кнопки, текстового поля и выпадающего списка:
| textBox1, свойство | Значение |
|---|---|
| Name | txtMenuText |
| Text |
| comboBox1, свойство | Значение |
|---|---|
| Name | cmbShortCuts |
| Text |
| button1, свойство | Значение |
|---|---|
| Name | btnAdd |
| Text | Добавить |
Добавляем на форму элементы управления ContextMenu и ColorDialog. Свойству СontextMenu формы Form1 устанавливаем значение добавленного контекстного меню — сontextMenu1. Вводим пункты контекстного меню:
| Name | Text | Shortcut |
|---|---|---|
| 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).
При внесении значений параметров пользователем или заполнении регистрационной формы требуется проверять вводимый текст по заданным критериям. Например, регистрационный номер не должен содержать букв. Рассмотрим проверку, которую можно осуществлять, используя встроенные события текстового поля. Скопируйте папку приложения 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 удобно применять, когда нужно выводить небольшую иконку в случае ошибки ввода. Скопируйте папку 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.
| Свойство | Описание | Значение по умолчанию |
|---|---|---|
| Blinkrate | Частота мерцания в миллисекундах | 250 |
| BlinkStyle | Стиль появления иконки. Возможны следующие варианты: BlinkIfDifferentError – иконка появляется при ошибке, мерцает несколько раз и останавливается;AlwaysBlink – при ошибке иконка мерцает постоянно;NeverBlink – иконка появляется, но не мерцает | BlinkIfDifferentError |
| Icon | Изображение иконки. Можно использовать другие файлы иконок (.ico) | (Icon) |
На диске, прилагаемом к книге, вы найдете приложение ErrorProvider (Code\Glava3\ ErrorProvider).
Одинаковая группа элементов с привязанными обработчиками может требоваться в нескольких частях большого приложения или даже нескольких приложений. Например, программы 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).
Некоторые программы, такие как словари и антивирусы, при запуске остаются в области уведомлений панели задач, откуда их можно развернуть, дважды щелкнув на иконке приложения (рис. 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-сериализацией. Обратный процесс — восстановление записанной информации — называется
Создайте новое 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. Запустившийся редактор содержит шесть
| Разделы | Описание |
|---|---|
| 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 | Содержатся динамические данные о состоянии различных устройств, установленных на компьютере пользователя |
Конечным элементом дерева реестра являются ключи или параметры, среди которых можно выделить три основных типа:
Основным классом для работы с реестром (создание новых ключей, их удаление и изменение) в библиотеке .NET Framework является RegistryKey. Описание некоторых методов этого класса приводится в таблице 3.4.
| Метод | Описание |
|---|---|
| CreateSubKey | Создание нового параметра реестра или открытие существующего. Название не чувствительно к регистру |
| DeleteSubKey | Удаление существующего параметра |
| DeleteSubKeyTree | Удаление существующего раздела и вложенных подразделов |
| DeleteValue | Удаление значения существующего параметра |
| OpenSubKey | Получение значения парметра только для чтения |
| SetValue | Установка значения |
| GetValue | Получение значения параметра |
| Close | Закрывание параметра и запись его содержимого на постоянной основе |
Вернемся к сохранению настроек приложения — теперь для записи размеров формы мы будем создавать и использовать ключи реестра. Создайте новое Windows-приложение и назовите его RegistrySettings. Подключаем пространство имен для работы с классом RegistryKey:
using Microsoft.Win32;
Снова создаем класс FormSize:
public class FormSize
{
public int height;
public int width;
}
В обработчике события Closing формы создаем раздел реестра RegApplication, в котором будут храниться данные:
private void Form1_Closing(object sender,
System.ComponentModel.CancelEventArgs e)
{
FormSize frmSize = new FormSize();
frmSize.height = this.Height;
frmSize.width = this.Width;
//Открываем раздел RegApplication
RegistryKey regkey = Registry.CurrentUser.OpenSubKey
("SOFTWARE\\Microsoft\\RegApplication", true);
//Если раздел не обнаружен, создаем его
if (regkey ==null)
{
RegistryKey newregkey = Registry.CurrentUser.OpenSubKey
("SOFTWARE\\Microsoft", true);
regkey = newregkey.CreateSubKey("RegApplication");
}
//Записываем значения ширины и высоты формы в ключи Height и Width
regkey.SetValue("Height", frmSize.height);
regkey.SetValue("Width", frmSize.width);
}
Запускаем приложение, изменяем размер, закрываем его и добавляем обработчик для события Load формы:
private void Form1_Load(object sender, System.EventArgs e)
{
FormSize frmSizeSetup = new FormSize();
//Открываем раздел реестра
RegistryKey regkey = Registry.CurrentUser.OpenSubKey
("SOFTWARE\\Microsoft\\RegApplication");
//Получаем значения ключей Height и Width
if (regkey!=null)
{
frmSizeSetup.height = Convert.ToInt32(regkey.GetValue("Height"));
frmSizeSetup.width = Convert.ToInt32(regkey.GetValue("Width"));
//Устанавливаем текущие значения ширины и высоты формы
this.Height = frmSizeSetup.height;
this.Width = frmSizeSetup.width;
}
}
При перезапуске приложения его измененный размер сохраняется. В реестре появился раздел RegApplication, в котором и находятся два ключа Height и Width со значениями размеров формы в пикселях (рис. 3.21):
(рис 3.21) Раздел RegApplication с двоичными ключами Height и WidthНа диске, прилагаемом к книге, вы найдете приложение RegistrySettings (Code\Glava3\ RegistrySettings).
До сих пор мы рассматривали небольшие программки, которые создавали сами. Теперь мы приступим к рассмотрению блоков достаточно большой программы – почтового клиента 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. Проекты, объединенные в рамках одного решения, являются связанными, а не внедренными. В этом нетрудно убедиться, переименовав папку одного из проектов или внеся изменения в код: в первом случае в результирующем решении будет ошибка, во втором – изменения затронут листинги и в решении.
Во многих программах, когда требуется получить последовательный ряд каких-либо значений, диалоговые окна представляют в виде
(рис 3.24) Мастер регистрации пользователяФорма Мастера появляется при выборе пункта главного меню "Новый пользователь"
private void itemNewUser_Click(object sender, System.EventArgs e)
{
//Создаем экземпляр wizard формы CreateUserWizard
CreateUserWizard wizard = new CreateUserWizard();
//Показываем форму:
wizard.ShowDialog();
…
}
Форма
(рис 3.25) Родительская форма CreateUserWizard и дочерние формы CUWStep1, CUWStep2, CUWStep3 в режиме дизайнаОбратите внимание на заголовок запущенной формы — к нему добавляются названия дочерних форм. После запуска формы в нее загружается форма 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, но также родительскую форму , которая, в свою очередь, является дочерней по отношению к главной форме mainForm. Родительская форма будет активной в этот момент, поэтому метод 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;
}
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)
{
}
}
}
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)
{
}
}
}
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)
{
}
}
}
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)
{
}
}
}
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)
{
}
}
}
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;
}
}
}
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));
}
}
}
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();
}
}
}
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;
}
}
}
//#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);
}
}
}
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();
}
}
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
}
}
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
}
}
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
}
}
//#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
}
}
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);
}
}
}
Форма
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();
}
}
}
Значения свойства 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();
}
}
}
}
Значения свойства 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("Значение порта должно быть числом");
}
}
}
}
}
Значения свойства 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");
}
}
}
}
Главная форма программы представляет собой контейнер для других форм и поэтому содержит сравнительно мало элементов управления. Значения свойства 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();
}
}
}
Значения свойства 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);
}
}
}
}
Для получения почты необходимо ввести пароль к своей учетной записи. Значения свойства 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();
}
}
}
}
Форма выбора пользователя появляется при запуске программы, она также используется для смены пользователя. Значения свойства 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();
}
}
}
На этой форме подготавливается сообщение к отправке. Значения свойства 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();
}
}
}
В эту форму загружается сообщение для чтения при его выборе из списка формы 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 предназначена для перемещения и копирования объектов при помощи мыши. Выделив фрагмент текста в 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).
При размещении на форме элемента управления в режиме дизайна, среда создает код в области Windows Form Designer generated code, описывающий этот элемент. Если мы назначим в обработчике заданного элемента управления генерацию аналогичного кода, то в запущенном приложении можно будет добавлять на форму другие элементы, активизируя этот обработчик. Для добавления элементов управления используется объект ControlsCollection, содержащий ряд методов (см. таблицу 3.1). Под коллекцией элементов понимается их упорядоченная последовательность.
| Метод | Описание |
|---|---|
| Add | Добавление элемента в коллекцию |
| AddRange | Добавление массива элементов |
| Clear | Удаление всех элементов из коллекции |
| Remove | Удаление элемента из коллекции |
| RemoveAt | Удаление элемента по заданному индексу |
| Count | Общее число элементов в коллекции |
Рассмотрим на практике добавление элементов управления. Создайте новое приложение и назовите его RegistrationForm. Располагаем на форме три надписи, два текстовых поля, кнопку, элементы CheckBox и (рис. 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 вставляем скопированный код из обработчика чекбокса. При выборе второго переключателя вся группа элементов, содержащаяся в , будет удалена, а затем в новую группу добавятся два текстовых поля и две надписи:
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).
В зависимости от различных событий, происходящих на форме, содержание контекстного меню может меняться. Создайте новое приложение и назовите его MenuRunTime. Добавляем на форму элемент управления (контейнер) и размещаем внутри него две надписи, текстовое поле, кнопку, ComboBox (выпадающий список) (см. рис. 3.6).
(рис 3.6) Приложение MenuRunTime в режиме дизайнаУстанавливаем следующие свойства кнопки, текстового поля и выпадающего списка:
| textBox1, свойство | Значение |
|---|---|
| Name | txtMenuText |
| Text |
| comboBox1, свойство | Значение |
|---|---|
| Name | cmbShortCuts |
| Text |
| button1, свойство | Значение |
|---|---|
| Name | btnAdd |
| Text | Добавить |
Добавляем на форму элементы управления ContextMenu и ColorDialog. Свойству СontextMenu формы Form1 устанавливаем значение добавленного контекстного меню — сontextMenu1. Вводим пункты контекстного меню:
| Name | Text | Shortcut |
|---|---|---|
| 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).
При внесении значений параметров пользователем или заполнении регистрационной формы требуется проверять вводимый текст по заданным критериям. Например, регистрационный номер не должен содержать букв. Рассмотрим проверку, которую можно осуществлять, используя встроенные события текстового поля. Скопируйте папку приложения 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 удобно применять, когда нужно выводить небольшую иконку в случае ошибки ввода. Скопируйте папку 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.
| Свойство | Описание | Значение по умолчанию |
|---|---|---|
| Blinkrate | Частота мерцания в миллисекундах | 250 |
| BlinkStyle | Стиль появления иконки. Возможны следующие варианты: BlinkIfDifferentError – иконка появляется при ошибке, мерцает несколько раз и останавливается;AlwaysBlink – при ошибке иконка мерцает постоянно;NeverBlink – иконка появляется, но не мерцает | BlinkIfDifferentError |
| Icon | Изображение иконки. Можно использовать другие файлы иконок (.ico) | (Icon) |
На диске, прилагаемом к книге, вы найдете приложение ErrorProvider (Code\Glava3\ ErrorProvider).
Одинаковая группа элементов с привязанными обработчиками может требоваться в нескольких частях большого приложения или даже нескольких приложений. Например, программы 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).
Некоторые программы, такие как словари и антивирусы, при запуске остаются в области уведомлений панели задач, откуда их можно развернуть, дважды щелкнув на иконке приложения (рис. 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-сериализацией. Обратный процесс — восстановление записанной информации — называется
Создайте новое 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. Запустившийся редактор содержит шесть
| Разделы | Описание |
|---|---|
| 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 | Содержатся динамические данные о состоянии различных устройств, установленных на компьютере пользователя |
Конечным элементом дерева реестра являются ключи или параметры, среди которых можно выделить три основных типа:
Основным классом для работы с реестром (создание новых ключей, их удаление и изменение) в библиотеке .NET Framework является RegistryKey. Описание некоторых методов этого класса приводится в таблице 3.4.
| Метод | Описание |
|---|---|
| CreateSubKey | Создание нового параметра реестра или открытие существующего. Название не чувствительно к регистру |
| DeleteSubKey | Удаление существующего параметра |
| DeleteSubKeyTree | Удаление существующего раздела и вложенных подразделов |
| DeleteValue | Удаление значения существующего параметра |
| OpenSubKey | Получение значения парметра только для чтения |
| SetValue | Установка значения |
| GetValue | Получение значения параметра |
| Close | Закрывание параметра и запись его содержимого на постоянной основе |
Вернемся к сохранению настроек приложения — теперь для записи размеров формы мы будем создавать и использовать ключи реестра. Создайте новое Windows-приложение и назовите его RegistrySettings. Подключаем пространство имен для работы с классом RegistryKey:
using Microsoft.Win32;
Снова создаем класс FormSize:
public class FormSize
{
public int height;
public int width;
}
В обработчике события Closing формы создаем раздел реестра RegApplication, в котором будут храниться данные:
private void Form1_Closing(object sender,
System.ComponentModel.CancelEventArgs e)
{
FormSize frmSize = new FormSize();
frmSize.height = this.Height;
frmSize.width = this.Width;
//Открываем раздел RegApplication
RegistryKey regkey = Registry.CurrentUser.OpenSubKey
("SOFTWARE\\Microsoft\\RegApplication", true);
//Если раздел не обнаружен, создаем его
if (regkey ==null)
{
RegistryKey newregkey = Registry.CurrentUser.OpenSubKey
("SOFTWARE\\Microsoft", true);
regkey = newregkey.CreateSubKey("RegApplication");
}
//Записываем значения ширины и высоты формы в ключи Height и Width
regkey.SetValue("Height", frmSize.height);
regkey.SetValue("Width", frmSize.width);
}
Запускаем приложение, изменяем размер, закрываем его и добавляем обработчик для события Load формы:
private void Form1_Load(object sender, System.EventArgs e)
{
FormSize frmSizeSetup = new FormSize();
//Открываем раздел реестра
RegistryKey regkey = Registry.CurrentUser.OpenSubKey
("SOFTWARE\\Microsoft\\RegApplication");
//Получаем значения ключей Height и Width
if (regkey!=null)
{
frmSizeSetup.height = Convert.ToInt32(regkey.GetValue("Height"));
frmSizeSetup.width = Convert.ToInt32(regkey.GetValue("Width"));
//Устанавливаем текущие значения ширины и высоты формы
this.Height = frmSizeSetup.height;
this.Width = frmSizeSetup.width;
}
}
При перезапуске приложения его измененный размер сохраняется. В реестре появился раздел RegApplication, в котором и находятся два ключа Height и Width со значениями размеров формы в пикселях (рис. 3.21):
(рис 3.21) Раздел RegApplication с двоичными ключами Height и WidthНа диске, прилагаемом к книге, вы найдете приложение RegistrySettings (Code\Glava3\ RegistrySettings).
До сих пор мы рассматривали небольшие программки, которые создавали сами. Теперь мы приступим к рассмотрению блоков достаточно большой программы – почтового клиента 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. Проекты, объединенные в рамках одного решения, являются связанными, а не внедренными. В этом нетрудно убедиться, переименовав папку одного из проектов или внеся изменения в код: в первом случае в результирующем решении будет ошибка, во втором – изменения затронут листинги и в решении.
Во многих программах, когда требуется получить последовательный ряд каких-либо значений, диалоговые окна представляют в виде
(рис 3.24) Мастер регистрации пользователяФорма Мастера появляется при выборе пункта главного меню "Новый пользователь"
private void itemNewUser_Click(object sender, System.EventArgs e)
{
//Создаем экземпляр wizard формы CreateUserWizard
CreateUserWizard wizard = new CreateUserWizard();
//Показываем форму:
wizard.ShowDialog();
…
}
Форма
(рис 3.25) Родительская форма CreateUserWizard и дочерние формы CUWStep1, CUWStep2, CUWStep3 в режиме дизайнаОбратите внимание на заголовок запущенной формы — к нему добавляются названия дочерних форм. После запуска формы в нее загружается форма 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, но также родительскую форму , которая, в свою очередь, является дочерней по отношению к главной форме mainForm. Родительская форма будет активной в этот момент, поэтому метод 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;
}
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)
{
}
}
}
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)
{
}
}
}
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)
{
}
}
}
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)
{
}
}
}
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)
{
}
}
}
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;
}
}
}
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));
}
}
}
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();
}
}
}
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;
}
}
}
//#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);
}
}
}
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();
}
}
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
}
}
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
}
}
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
}
}
//#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
}
}
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);
}
}
}
Форма
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();
}
}
}
Значения свойства 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();
}
}
}
}
Значения свойства 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("Значение порта должно быть числом");
}
}
}
}
}
Значения свойства 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");
}
}
}
}
Главная форма программы представляет собой контейнер для других форм и поэтому содержит сравнительно мало элементов управления. Значения свойства 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();
}
}
}
Значения свойства 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);
}
}
}
}
Для получения почты необходимо ввести пароль к своей учетной записи. Значения свойства 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();
}
}
}
}
Форма выбора пользователя появляется при запуске программы, она также используется для смены пользователя. Значения свойства 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();
}
}
}
На этой форме подготавливается сообщение к отправке. Значения свойства 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();
}
}
}
В эту форму загружается сообщение для чтения при его выборе из списка формы 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);
}
}
}
}
Для получения официальных документов о завершении программы дополнительного профессионального образования (удостоверения о повышении квалификации, дипломов о профессиональной переподготовке и MBA) необходимо предоставить:
Внимание! Вы можете не заказывать доставку бумажной версии официального документы, а скачать его в электронном виде и распечатать самостоятельно. Информация о выданном документе в течение 1 месяца загружается в Федеральную информационную систему «Федеральный реестр сведений о документах об образовании и (или) о квалификации, документах об обучении» - ФИС ФРДО.
Доступ на новый сайт осуществляется с использованием адреса электронной почты, который был указан вами при регистрации на "старом". Мы постарались перенести все ваши данные с прежнего ресурса, однако не исключена вероятность потери части информации.
При возникновении проблемы со входом, воспользуйтесь функцией сброса пароля
Если вы обнаружите несоответствия, пожалуйста, сообщите нам.