Элементы управления — это компоненты, обеспечивающие взаимодействие между пользователем и программой. Среда Visual Studio.NET предоставляет большое количество элементов, которые можно сгруппировать по нескольким функциональным группам.
Группа командных объектов
Элементы управления Button, LinkLabel, ToolBar реагируют на нажатие кнопки мыши и немедленно запускают какое-либо действие. Наиболее распространенная группа элементов.
Группа текстовых объектов
Большинство приложений предоставляют возможность пользователю вводить текст и, в свою
Группа переключателей
Приложение может содержать несколько предопределенных вариантов выполнения действия или задачи; элементы управления этой группы предоставляют возможность выбора пользователю. Это одна из самых обширных групп элементов, в которую входят ComboBox, ListBox, ListView, TreeView, NumericUpDown и многие другие.
Группа контейнеров
С элементами этой группы действия приложения практически никогда не связываются, но они имеют большое значение для организации других элементов управления, их группировки и общего дизайна формы. Как правило, элементы этой группы, расположенные на форме, служат подложкой кнопкам, текстовым полям, спискам — поэтому они и называются контейнерами. Элементы Panel,
Группа графических элементов
Даже самое простое приложение Windows содержит графику — иконки, заставку, встроенные изображения. Для размещения и отображения их на форме используются элементы для работы с графикой — Image List, Picture Box.
Диалоговые окна
Выполняя различные операции с документом — открытие, сохранение, печать, предварительный просмотр, — мы сталкиваемся с соответствующими диалоговыми окнами. Разработчикам .NET не приходится заниматься созданием окон стандартных процедур: элементы OpenFileDialog, SaveFile Dialog, ColorDialog, PrintDialog содержат уже готовые операции.
Группа меню
Многие пользователи настраивают интерфейс приложений на свой вкус: одним нравится наличие определенных панелей инструментов, другим – индивидуальное расположение окон. Но в любом приложении будет присутствовать меню, содержащее в себе доступ ко всем возможностям и настройкам приложения. Элементы MainMenu, ContextMenu представляют собой готовые формы для внесения заголовков и пунктов меню.
Практическая работа с различными элементами управления будет рассмотрена в этой и последующих лекциях.
Большинство Windows-приложений оснащено главным меню, которое представляет собой иерархическую структуру выполняемых функций и команд. Практически все функции, которые можно осуществить при помощи элементов управления, имеют свой аналог в виде пункта меню.
Для создания главного меню используется элемент управления MainMenu, расположенный на панели инструментов ToolBox. Создайте новое приложение и назовите его NotepadCSharp. Установите следующие свойства формы:
| Form1, форма, свойство | Значение |
|---|---|
| Name | frmmain |
| Icon | Code\Glava2\NotepadCSharp\Icon\README.ICO |
| Text | Notepad C# |
| Maximized |
Перетаскиваем элемент управления на форму. Нам предстоит заполнить строки меню следующими пунктами (рис. 2.1):
(рис 2.1) Пункты главного меню приложения Notepad C#Каждый пункт главного меню имеет свое окно свойств, в котором, подобно другим элементам управления, задаются значения свойств Name и Text (рис. 2.2). В поле Text перед словом New стоит знак — так называемый амперсанд, указывающий, что N должно быть подчеркнута и будет частью встроенного клавиатурного интерфейса Windows. Когда пользователь на клавиатуре нажимает клавишу Alt и затем N, выводится подменю New.
(рис 2.2) Свойства пункта меню NewВ Windows есть еще интерфейс для работы с так называемыми быстрыми клавишами, или
| Name | Text | Shortcut |
|---|---|---|
| mnuFile | File | |
| mnuNew | New | CtrlN |
| mnuOpen | Open | CtrlO |
| mnuSave | Save | CtrlS |
| menuItem5 | - | |
| mnuExit | Exit | AltF4 |
| mnuEdit | Edit | |
| mnuCut | Cut | CtrlX |
| mnuCopy | Copy | CtrlC |
| mnuPaste | Paste | CtrlV |
| mnuDelete | Delete | Del |
| mnuSelectAll | SelectAll | CtrlA |
| mnuFormat | Format | |
| mnuFont | Font… | |
| mnuColor | Color… | |
| mnuWindow | Window | |
| mnuArrangeIcons | Arrange Icons | |
| mnuCascade | Cascade | |
| mnuTileHorizontal | Tile Horizontal | |
| mnuTileVertical | Tile Vertical | |
| mnuHelp | ? | |
| mnuAbout | About Programm... |
Вы можете самостоятельно выбрать сочетания клавиш, не указанные в табл. 2.1, для соответствующих пунктов меню.
Такие программы, как блокнот и

(рис 2.4) SDI приложение Microsoft Paint(рис 2.3) MDI-приложение Adobe PhotoshopВ MDI-приложениях главная форма содержит в себе несколько документов, каждый из которых является холстом в графических программах или полем для текста в редакторах. Продолжим работу над приложением Notepad C#. В окне Solution Explorer щелкаем правой кнопкой на имени проекта и в появившемся контекстном меню выбираем Add/ Add Windows Form… . В появившемся окне называем форму – blank.cs. В нашем проекте появилась новая форма — будем называть ее дочерней. В режиме дизайна перетаскиваем на нее элемент управления RichTextBox: в отличие от элемента textBox, размер содержимого текста в нем не ограничивается 64 Кб; кроме того, RichTextBox позволяет редактировать цвет текста, добавлять изображения. Свойству Dock этого элемента устанавливаем значение Fill (рис. 2.5):
(рис 2.5) Свойство Dock элемента RichTextBoxПереходим в режим дизайна формы Frmmain и устанавливаем свойству IsMdiContainer значение true. Цвет формы при этом становится темно-серым. Новые документы будут у нас появляться при нажатии пункта меню New (которому мы установили сочетание клавиш Ctrl+N), поэтому дважды щелкаем в этом пункте и переходим в код:
private void mnuNew_Click(object sender, System.EventArgs e)
{
//Создаем новый экземпляр формы frm
blank frm = new blank();
//Указываем, что родительским контейнером
//нового экземпляра будет эта, главная форма.
frm.MdiParent = this;
//Вызываем форму
frm.Show();
}
Запускаем приложение. Теперь при нажатии клавиш Ctrl+N или выборе пункта меню New появляется несколько окон, расположенных каскадом. Однако заголовок у них всех одинаковый — blank. При создании нескольких документов, например в Microsoft Word, они называются ДокументN, где N — номер документа. Переключаемся в код формы blank, и в классе blank объявляем переменную DocName:
public string DocName = "";
Переключаемся в код формы frmmain и в классе frmmain объявляем переменную openDocuments:
private int openDocuments = 0;
Присваиваем переменной DocName часть названия по шаблону, в который включен счетчик числа открываемых документов, затем это значение передаем свойству Text создаваемой формы frm:
private void mnuNew_Click(object sender, System.EventArgs e)
{
blank frm = new blank();
frm.DocName = "Untitled " + ++openDocuments;
frm.Text = frm.DocName;
frm.MdiParent = this;
frm.Show();
}
Запускаем приложение. Теперь новые документы содержат разные заголовки (рис. 2.6).
(рис 2.6) Новые документы имеют упорядоченные названия
При работе с несколькими документами в MDI-приложениях удобно упорядочивать их на экране. Можно, конечно, распределять формы вручную, но при работе с большим количеством документов это представляется затруднительным. В пункте меню Window реализуем процедуру выравнивания окон.
Создаем обработчиков:
private void mnuArrangeIcons_Click(object sender, System.EventArgs e)
{
this.LayoutMdi(MdiLayout.ArrangeIcons);
}
private void mnuCascade_Click(object sender, System.EventArgs e)
{
this.LayoutMdi(MdiLayout.Cascade);
}
private void mnuTileHorizontal_Click(object sender, System.EventArgs e)
{
this.LayoutMdi(MdiLayout.TileHorizontal);
}
private void mnuTileVertical_Click(object sender, System.EventArgs e)
{
this.LayoutMdi(MdiLayout.TileVertical);
}
Метод LayoutMdi содержит перечисление MdiLayout, содержащее четыре члена. ArrangeIcons переключает фокус на выбранную форму, в свойстве MdiList пункта меню ArrangeIcons устанавливаем также значение true. При открытии нескольких новых документов окна располагаются каскадом (рис. 2.6), их можно расположить горизонтально — значение TileHorizontal или вертикально — значение TileVertical, а затем снова вернуть каскадное расположение — Cascade (рис. 2.7):
(рис 2.7) Расположение окон TileHorizontal и пункт меню ArrangeIcons
С приложением работать будет удобней, если при создании нового документа он сразу будет занимать всю область главной формы. Для этого установим свойство blank Maximized. Теперь приступим к созданию обработчиков для стандартных операций вырезания, копирования и вставки. Элемент управления RichTextBox имеет свойство SelectedText, которое содержит выделенный фрагмент текста. На основании этого свойства и будут реализованы действия по работе с текстом. В коде формы blank объявляем переменную BufferText, в которой будет храниться буферизованный фрагмент текста:
private string BufferText = "";
Далее создаем соответствующие методы:
// Вырезание текста
public void Cut()
{
this.BufferText = richTextBox1.SelectedText;
richTextBox1.SelectedText = "";
}
// Копирование текста
public void Copy()
{
this.BufferText = richTextBox1.SelectedText;
}
// Вставка
public void Paste()
{
richTextBox1.SelectedText = this.BufferText;
}
// Выделение всего текста — используем свойство SelectAll элемента управления RichTextBox
public void SelectAll()
{
richTextBox1.SelectAll();
}
// Удаление
public void Delete()
{
richTextBox1.SelectedText = "";
this.BufferText = "";
}
Переключаемся в режим дизайна формы и создаем обработчиков для пунктов меню:
private void mnuCut_Click(object sender, System.EventArgs e)
{
blank frm = (blank)this.ActiveMdiChild;
frm.Cut();
}
private void mnuCopy_Click(object sender, System.EventArgs e)
{
blank frm = (blank)this.ActiveMdiChild;
frm.Copy();
}
private void mnuPaste_Click(object sender, System.EventArgs e)
{
blank frm = (blank)this.ActiveMdiChild;
frm.Paste();
}
private void mnuDelete_Click(object sender, System.EventArgs e)
{
blank frm = (blank)this.ActiveMdiChild;
frm.Delete();
}
private void mnuSelectAll_Click(object sender, System.EventArgs e)
{
blank frm = (blank)this.ActiveMdiChild;
frm.SelectAll();
}
Свойство ActiveMdiChild переключает фокус на текущую форму, если их открыто несколько, и вызывает один из методов, определенных в дочерней форме. Запускаем приложение. Теперь мы можем выполнять все стандартные операции с текстом.
Контекстное меню, дублирующее некоторые действия основного меню, — не самый быстрый способ работы с программой, но самый привычный для пользователя. Элемент управления TextBox содержит в себе простейшее контекстное меню, дублирующее действия подменю Edit. Для того чтобы убедиться в этом, достаточно нанести этот элемент управления на форму и запустить приложение (рис. 2.8):
(рис 2.8) Контекстное меню элемента TextBoxВ нашем приложении Notepad C# в качестве текстового элемента мы используем RichTextBox. Добавим элемент управления contextMenu из окна ToolBox на форму blank. Добавляем пункты контекстного меню точно так же, как мы это делали для главного меню (рис. 2.9):
(рис 2.9) Пункты контекстного менюСвойство Text и Shortcut пунктов меню оставляем прежними. Если мы установим затем для свойства ShowShortcut значение false, то сочетания клавиш будут работать, но в самом меню отображаться не будут — как на рис. рис. 2.8. Свойство Name будет формироваться следующим образом: для пункта Cut — cmnuCut, для Сopy — cmnuCopy и т.д.
В обработчике пунктов просто вызываем соответствующие методы:
private void cmnuCut_Click(object sender, System.EventArgs e)
{
Cut();
}
private void cmnuCopy_Click(object sender, System.EventArgs e)
{
Copy();
}
private void cmnuPaste_Click(object sender, System.EventArgs e)
{
Paste();
}
private void cmnuDelete_Click(object sender, System.EventArgs e)
{
Delete();
}
private void cmnuSelectAll_Click(object sender, System.EventArgs e)
{
SelectAll();
}
Последнее, что нам осталось сделать, — это определить, где будет появляться контекстное меню. Элемент RichTextBox, так же как и формы frmmain и blank, имеет свойство ContextMenu, где мы и указываем contextMenu1, поскольку нам нужно отображать меню именно в текстовом поле. Запускаем приложение — теперь в любой точке текста доступно меню (рис. 2.10).
(рис 2.10) Контекстное меню
Среда Visual Studio .NET содержит готовые диалоговые окна, предлагающие выбрать файл для открывания или путь на диске для сохранений текущего файла (рис. 2.11).
(рис 2.11) Диалоговое окно открытия файлаМы рассмотрим одну часть диалоговых окон в этой лекции, а другую, относящуюся к подготовке документа к печати, — в лекции 6.
Добавьте на форму frmmain элемент управления OpenFileDialog из окна панели инструментов ToolBox. Подобно элементу MainMenu, он будет располагаться на панели невидимых компонент (рис. 2.12):
(рис 2.12) Добавление OpenFileDialog на формуСвойство FileName задает название файла, которое будет находиться в поле "Имя файла:" при появлении диалога. На рис. рис. 2.12 название в этом поле — "Текстовые файлы", поскольку на рис. рис. 2.11 был введен именно этот текст. Свойство Filter задает ограничение файлов, которые могут быть выбраны для открытия — в окне будут показываться только файлы с заданным расширением. Через вертикальную разделительную линию можно задать смену типа расширения, отображаемого в выпадающем списке "Тип файлов". Здесь введено Text Files (*.txt)|*.txt|All Files(*.*)|*.* что означает обзор либо текстовых файлов, либо всех. Свойство InitialDirectory позволяет задать директорию, откуда будет начинаться обзор. Если это свойство не установлено, исходной директорией будет рабочий стол.
Для работы с файловыми потоками в коде формы blank подключаем пространство имен System.IO:
using System.IO;
В методе Open считываем содержимое файла в RichTextBox:
//Создаем метод Open, в качестве параметра объявляем строку адреса файла.
public void Open(string OpenFileName)
{
//Если файл не выбран, возвращаемся назад (появится встроенное предупреждение)
if (OpenFileName == "")
{
return;
}
else
{
//Создаем новый объект StreamReader и передаем ему переменную //OpenFileName
StreamReader sr = new StreamReader(OpenFileName);
//Читаем весь файл и записываем его в richTextBox1
richTextBox1.Text = sr.ReadToEnd();
// Закрываем поток
sr.Close();
//Переменной DocName присваиваем адресную строку
DocName = OpenFileName;
}
}
Добавим обработчик пункта меню Open формы frmmain:
private void mnuOpen_Click(object sender, System.EventArgs e)
{
//Можно программно задавать доступные для обзора расширения файлов
//openFileDialog1.Filter = "Text Files (*.txt)|*.txt|All Files(*.*)|*.*";
//Если выбран диалог открытия файла, выполняем условие
if (openFileDialog1.ShowDialog() == DialogResult.OK)
{
//Создаем новый документ
blank frm = new blank();
//Вызываем метод Open формы blank
frm.Open(openFileDialog1.FileName);
//Указываем, что родительской формой является форма frmmain
frm.MdiParent = this;
//Присваиваем переменной DocName имя открываемого файла
frm.DocName = openFileDialog1.FileName;
//Свойству Text формы присваиваем переменную DocName
frm.Text = frm.DocName;
//Вызываем форму frm
frm.Show();
}
}
Запускаем приложение и открываем текстовый файл, сохраненный в формате блокнота (рис. 2.13).
(рис 2.13) Заголовок формы представляет собой адрес и имя открытого файлаДля корректного чтения кириллицы текст в блокноте должен быть сохранен в кодировке Unicode. К сожалению, встроенные диалоговые окна OpenFileDialog Visual Studio .NET не содержат дополнительного поля, позволяющего выбирать кодировку файла при его открытии или сохранении, как это реализовано, например, в блокноте.
Для сохранения файлов добавляем на форму frmmain элемент управления saveFileDialog1. Cвойства этого диалога в точности такие же, как у OpenFileDialog (рис. 2.12). Переходим в код формы blank:
//Создаем метод Save, в качестве параметра объявляем строку адреса файла.
public void Save(string SaveFileName)
{
//Если файл не выбран, возвращаемся назад (появится встроенное предупреждение)
if (SaveFileName == "")
{
return;
}
else
{
//Создаем новый объект StreamWriter и передаем ему переменную //OpenFileName
StreamWriter sw = new StreamWriter(SaveFileName);
//Содержимое richTextBox1 записываем в файл
sw.WriteLine(richTextBox1.Text);
//Закрываем поток
sw.Close();
//Устанавливаем в качестве имени документа название сохраненного файла
DocName = SaveFileName;
}
}
Добавляем обработчик пункта меню Save формы frmmain:
private void mnuSave_Click(object sender, System.EventArgs e)
{
//Можно программно задавать доступные для обзора расширения файлов
//openFileDialog1.Filter = "Text Files (*.txt)|*.txt|All Files(*.*)|*.*";
//Если выбран диалог открытия файла, выполняем условие
if (saveFileDialog1.ShowDialog() == DialogResult.OK)
{
//Переключаем фокус на данную форму.
blank frm = (blank)this.ActiveMdiChild;
//Вызываем метод Save формы blank
frm.Save(saveFileDialog1.FileName);
//Указываем, что родительской формой является форма frmmain
frm.MdiParent = this;
//Присваиваем переменной FileName имя сохраняемого файла
frm.DocName = saveFileDialog1.FileName;
//Свойству Text формы присваиваем переменную DocName
frm.Text = frm.DocName;
}
}
Запускаем приложение. Теперь файлы можно открывать, редактировать и сохранять. Однако, при сохранении внесенных изменений в уже сохраненном файле вместо его перезаписи вновь появляется окно SaveFileDialog. Изменим нашу программу так, чтобы можно было сохранять и перезаписывать файл. В конструкторе формы frmmain после InitializeComponent отключим доступность пункта меню Save:
mnuSave.Enabled = false;
Переключаемся в режим дизайна формы frmmain и добавляем пункт меню Save As после пункта Save. Устанавливаем следующие свойства этого пункта: Name — mnuSaveAs, Shortcut — CtrlShiftS, Text Save As. В обработчике Save As вставляем вырезанный обработчик пункта Save и добавляем включение доступности Save:
mnuSave.Enabled = true;
Сохранять изменения требуется как в только что сохраненных документах, так и в документах, созданных ранее и открытых для редактирования. Поэтому добавим в метод Open включение доступности пункта меню Save:
private void mnuOpen_Click(object sender, System.EventArgs e)
{
mnuSave.Enabled = true;
}
В обработчике пункта Save добавим простую перезапись файла — вызов метода Save формы blank:
private void mnuSave_Click(object sender, System.EventArgs e)
{
//Переключаем фокус на данную форму.
blank frm = (blank)this.ActiveMdiChild;
//Вызываем метод Save формы blank
frm.Save(frm.DocName);
}
Запускаем приложение. Теперь, если мы работаем с несохраненным документом, пункт Save неактивен (рис. 2.14), после сохранения он становится активным (рис. 2.15) и, кроме того, работает сочетание клавиш Ctrl+S. Можно сохранить копию текущего документа, вновь воспользовавшись пунктом меню Save As (рис. 2.16).

(рис 2.15) Новый документ(рис 2.14) Сохраненный документ
(рис 2.16) Сохранение копииКонечно, эту задачу можно решить более элегантно — совместив оба пункта сохранения документа в один. Но мне хотелось показать разницу между простым сохранением и перезаписью файлов, кроме того, мы научились отключать доступность пунктов меню.
Всякий раз, когда мы закрываем документ Microsoft Word, в который внесли изменения, появляется окно предупреждения, предлагающее сохранить документ. Добавим аналогичную функцию в наше приложение. В классе blank : System.Windows.Forms.Form формы blank создаем переменную, которая будет фиксировать сохранение документа:
public bool IsSaved = false;
В обработчик методов Save и Save As формы frmmain добавляем изменение значения этой переменной:
private void mnuSave_Click(object sender, System.EventArgs e)
{
…
frm.IsSaved = true;
}
private void mnuSaveAs_Click(object sender, System.EventArgs e)
{
…
frm.IsSaved = true;
}
Переходим в режим дизайна формы blank и в окне свойств переключаемся на события формы, щелкнув на значок с молнией. В поле события Closing дважды щелкаем и переходим в код:
private void blank_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
//Если переменная IsSaved имеет значение true, т. е. новый документ
//был сохранен (Save As) или в открытом документе были сохранены изменения (Save), то //выполняется условие
if(IsSaved ==true)
//Появляется диалоговое окно, предлагающее сохранить документ.
if(MessageBox.Show("Do you want save changes in " + this.DocName + "?",
"Message", MessageBoxButtons.YesNo,
MessageBoxIcon.Question) == DialogResult.Yes)
//Если была нажата кнопка Yes, вызываем метод Save
{
this.Save(this.DocName);
}
}
Запускаем приложение. При закрытии формы blank или frmmain появляется окно предупреждения (рис. 2.17):
(рис 2.17) Окно предупреждения при закрытии формы
При создании MDI-приложений приходится разделять код для открытия и сохранения файлов, как мы делали для приложения Notepad C#. В случае
| TextBox, свойство | Значение |
|---|---|
| Name | txtBox |
| Dock | Fill |
| Multiline | true |
| Text | Да |
Добавляем на форму элемент MainMenu, в котором будет всего три пункта — File, Open и Save (свойства этих пунктов см. в таблице 2.1). Из окна ToolBox перетаскиваем элементы OpenFileDialog и SaveFileDialog — свойства этих элементов в точности такие же, как и у диалогов приложения Notepad C#. Переходим в код формы. Подключаем пространство имен для работы с файловыми потоками:
using System.IO;
Добавляем обработчик для пункта меню Open:
private void mnuOpen_Click(object sender, System.EventArgs e)
{
//Показываем диалог выбора файла
openFileDialog1.ShowDialog();
// Переменной fileName присваиваем имя открываемого файла
string fileName = openFileDialog1.FileName;
//Создаем поток fs и открываем файл для чтения.
FileStream filestream= File.Open(fileName, FileMode.Open, FileAccess.Read);
//Проверяем, открыт ли поток, и если открыт, выполняем условие
if(filestream != null)
{
//Создаем объект streamreader и связываем его с потоком filestream
StreamReader streamreader = new StreamReader(filestream);
//Считываем весь файл и записываем его в TextBox
txtBox.Text = streamreader.ReadToEnd();
//Закрываем поток.
filestream.Close();
}
}
Добавляем обработчик для пункта меню Save:
private void mnuSave_Click(object sender, System.EventArgs e)
{
//Показываем диалог выбора файла
saveFileDialog1.ShowDialog();
// В качестве имени сохраняемого файла устанавливаем переменную fileName
string fileName=saveFileDialog1.FileName;
//Создаем поток fs и открываем файл для записи.
FileStream filestream = File.Open(fileName, FileMode.Create, FileAccess.Write);
//Проверяем, открыт ли поток, и если открыт, выполняем условие
if(filestream != null)
{
//Создаем объект streamwriter и связываем его с потоком filestream
StreamWriter streamwriter = new StreamWriter(filestream);
//Записываем данные из TextBox в файл
streamwriter.Write(txtBox.Text);
//Переносим данные из потока в файл
streamwriter.Flush();
//Закрываем поток
filestream.Close();
}
}
Запускаем приложение. Как уже отмечалось, элемент управления TextBox имеет встроенное контекстное меню, поддерживает сочетание клавиш для редактирования, а диалоговые окна открытия и сохранения позволяют этому простейшему приложению работать с внешними файлами.
На диске, прилагаемом к книге, вы найдете приложение TextEditor (Code\Glava2\TextEditor).
Продолжим работу над приложением Notepad C#. Добавим теперь возможность выбирать шрифт, его размер и начертание. В режиме дизайна перетащим на форму frmmain из окна ToolBox элемент управления FontDialog. Не изменяя ничего в свойствах этого элемента, переходим в обработчик пункта Font главного меню:
private void mnuFont_Click(object sender, System.EventArgs e)
{
//Переключаем фокус на данную форму.
blank frm = (blank)this.ActiveMdiChild;
//Указываем, что родительской формой является форма frmmain
frm.MdiParent = this;
//Вызываем диалог
fontDialog1.ShowColor = true;
//Связываем свойства SelectionFont и SelectionColor элемента RichTextBox
//с соответствующими свойствами диалога
fontDialog1.Font = frm.richTextBox1.SelectionFont;
fontDialog1.Color = frm.richTextBox1.SelectionColor;
//Если выбран диалог открытия файла, выполняем условие
if (fontDialog1.ShowDialog() == DialogResult.OK)
{
frm.richTextBox1.SelectionFont = fontDialog1.Font;
frm.richTextBox1.SelectionColor = fontDialog1.Color;
}
//Показываем форму
frm.Show();
}
Запускаем приложение, и в окне Output появляется список ошибок (рис. 2.18).
(рис 2.18) Список ошибок — NotepadCSharp.blank.richTextBox1 недоступен из-за своего уровня защитыВ чем же дело? При расположении на форме blank элемента управления RichTextBox среда Visual Studio.NET сгенерировала экземпляр richTextBox1 класса System.Windows.Forms.RichTextBox с модификатором доступа private, из-за чего при обращении к нему и возникает исключение:
private System.Windows.Forms.RichTextBox richTextBox1;
Изменим модификатор на public и снова запустим приложение. При выборе пункта меню Font теперь можно менять параметры текущего текста.
Диалоговое окно FontDialog содержит список цветов, которые могут быть применены к тексту, но предлагаемый список ограничен. Более интересной представляется возможность назначать пользовательский цвет, который может быть определен в большом диапазоне (рис. 2.19):
(рис 2.19) Диалоговое окно ColorDialogИз окна ToolBox добавляем элемент управления ColorDialog и, вновь не изменяя его свойств, переходим к обработчику пункта Color главного меню формы frmmain:
private void mnuColor_Click(object sender, System.EventArgs e)
{
blank frm = (blank)this.ActiveMdiChild;
frm.MdiParent = this;
colorDialog1.Color = frm.richTextBox1.SelectionColor;
if (colorDialog1.ShowDialog() == DialogResult.OK)
{
frm.richTextBox1.SelectionColor = colorDialog1.Color;
}
frm.Show();
}
Обратите внимание на то, что код для ColorDialog в точности такой же, как и часть кода для свойства Color диалога FontDialog. Это и не удивительно: ведь мы связываем эти диалоги со свойствами одного и того же объекта — RichTextBox.
Элемент управления StatusBar применяется в программах для вывода информации в строку состояния — небольшую полоску, расположенную внизу приложения. В Microsoft Word, например, на ней отображается количество страниц, язык ввода, состояние проверки правописания и другие параметры. Добавим к приложению Notepad C# строку состояния, на которой осуществляется подсчет вводимых символов и выводится системное время.
Добавляем на форму blank элемент управления StatusBar. Удаляем содержимое поля свойства Text. В поле свойства Panels щелкаем на кнопку (…). Открывается StatusBarCollectionEditor, в котором мы создаем панели для отображения. Создайте две панели, дважды щелкая на кнопке Add, и установите им следующие свойства (измененные значения выделяются жирным шрифтом) (рис. 2.20 и рис. 2.21):

(рис 2.21) Свойства панели sbAmount(рис 2.20) Свойства панели sbTimeЗначения некоторых свойств панели приводятся в таблице 2.2.
| Свойство | Значение |
|---|---|
| Alignment | Выравнивание содержимого свойства Text на панели |
| AutoSize | Изменение размеров панели по содержимому |
| BorderStyle | Внешний вид панели – утопленная, приподнятая или без выделения |
| Icon | Добавление иконки |
| Style | Стиль панели |
| Text | Текст, располагаемый на панели |
| ToolTipText | Всплывающая подсказка — появляется при наведении курсора на панель |
| Width | Ширина панели в пикселях |
| Name | Название панели для обращения к ней в коде |
Свойства панели, назначаемые в окне редактора StatusBarCollectionEditor, можно изменять в коде —именно так мы сейчас и поступим.
После завершения работы над панелями закрываем редактор. Свойству ShowPanels элемента управления StatusBar устанавливаем значение True. На форме немедленно отображаются две панели.
Выделяем элемент управления RichTextBox, в окне его свойств переключаемся на события и создаем обработчик для события TextChanged:
private void richTextBox1_TextChanged(object sender, System.EventArgs e)
{
//Свойству Text панели sbAmount устанавливаем надпись "Аmount of symbols"
//и длину текста в RichTextBox.
sbAmount.Text = "Аmount of symbols" + richTextBox1.Text.Length.ToString();
}
Свойство Text панели sbAmount мы изменяем программно: даже если бы мы ничего не написали в окне редактора StatusBarCollectionEditor, при возникновении события TextChanged на панели появится надпись.
Займемся теперь второй панелью — той, на которую будем выводить системное время. В конструкторе формы blank добавляем код:
public blank()
{
InitializeComponent();
//Свойству Text панели sbTime устанавливаем системное время,
// конвертировав его в тип String
sbTime.Text = Convert.ToString(System.DateTime.Now.ToLongTimeString());
//В тексте всплывающей подсказки выводим текущую дату
sbTime.ToolTipText = Convert.ToString(System.DateTime.Today.ToLongDateString());
}
Запускаем приложение. Панель с выводимым временем располагается достаточно необычно (рис. 2.22), при необходимости для вывода времени в привычном правом нижнем углу можно добавить третью пустую панель.
(рис 2.22) Строка состояния с двумя панелями
При запуске приложения Notepad С# на форме имеются три стандартные кнопки — "Свернуть", "Развернуть" и "Закрыть". Большинство пользователей предпочитают использовать именно кнопку "Закрыть" для выхода из приложения. Тем не менее принято дублировать кнопку формы пунктом меню Exit. В обработчике этой кнопки добавляем код
private void mnuExit_Click(object sender, System.EventArgs e)
{
this.Close();
}
Метод Close закрывает форму и может быть назначен другим элементам управления — например, кнопке.
Чекбоксы относятся к так называемым кнопкам
| FindForm, форма, свойство | Значение |
|---|---|
| Name | FindForm |
| FormBorderStyle | FixedToolWindow |
| Size | 328; 112 |
| Text | Find |
Располагаем на форме TextBox, две кнопки и два элемента CheckBox так, как показано на рис. рис. 2.23:
(рис 2.23) Форма FindForm в режиме дизайнаУстанавливаем следующие свойства элементам управления:
| TextBox, свойство | Значение |
|---|---|
| Name | txtFind |
| Size | 192; 20 |
| Text |
| checkBox1, свойство | Значение |
|---|---|
| Name | cbMatchCase |
| Text | Match Case |
| checkBox2, свойство | Значение |
|---|---|
| Name | cbMatchWhole |
| Text | Match whole word |
| button1, свойство | Значение |
|---|---|
| Name | btnOK |
| DialogResult | OK |
| Text | OK |
| button2, свойство | Значение |
|---|---|
| Name | btnCancel |
| DialogResult | Cancel |
| Text | Cancel |
Выбор первого чекбокса — cbMatchCase — будет устанавливать поиск слова с учетом регистра, второго – cbMatchWhole — поиск по целому слову. Обратите внимание на свойство кнопок DialogResult — выбирая соответствующие свойства, мы устанавливаем обработчики для кнопок без обращения к коду. Значение ОК закрывает форму, выполняя установленное действие, — в данном случае — поиск; значение Cancel просто закрывает форму. В главном меню формы frmmain добавляем разделительную линию и пункт Find и устанавливаем значения свойств: Name — mnuFind, Shortcut — CtrlF, Text — Find.
Переходим в обработчик этого пункта:
private void mnuFind_Click(object sender, System.EventArgs e)
{
//Создаем новый экземпляр формы FindForm
FindForm frm = new FindForm();
//Если выбран результат DialogResult.Cancel, закрываем форму (до этого
//мы использовали DialogResult.OK)
if(frm.ShowDialog(this) == DialogResult.Cancel) return;
////Переключаем фокус на данную форму.
blank form = (blank)this.ActiveMdiChild;
////Указываем, что родительской формой является форма frmmain
form.MdiParent = this;
//Вводим переменную для поиска в определенной части текста —
//поиск слова будет осуществляться от текущей позиции курсора
int start = form.richTextBox1.SelectionStart;
//Вызываем предопределенный метод Find элемента richTextBox1.
form.richTextBox1.Find(frm.FindText, start, frm.FindCondition);
}
Основой поиска будет метод Find элемента управления RichTextBox. Нам остается лишь указать параметры поиска, которые могут принимать различные значения (рис. 2.24):
(рис 2.24) Параметры метода Find. Щелкая на маленькую кнопку всплывающей подсказки Intel Sense, выбираем разные подсказки для групп передаваемых параметровВ коде формы FindForm осталось реализовать логику работы, зависящую от положения элементов CheckBox:
// Создаем перечисление, возвращающее параметр FindCondition
public RichTextBoxFinds FindCondition
{
get
{
//Выбраны два чекбокса
if (cbMatchCase.Checked cbMatchWhole.Checked)
{
// Возвращаем свойство MatchCase и WholeWord
return RichTextBoxFinds.MatchCase| RichTextBoxFinds.WholeWord;
}
//Выбран один чекбокс
if (cbMatchCase.Checked )
{
// Возвращаем свойство MatchCase
return RichTextBoxFinds.MatchCase;
}
//Выбран другой чекбокс
if (cbMatchWhole.Checked )
{
// Возвращаем свойство WholeWord
return RichTextBoxFinds.WholeWord;
}
//Не выбран ни один чекбокс
return RichTextBoxFinds.None;
}
}
И наконец, создаем свойство FindText, возвращающее в качестве переменной поиска введенный текст в текстовое поле формы FindForm:
public string FindText
{
get{return txtFind.Text;}
set{txtFind.Text = value;}
}
Запускаем приложение. Выбирая различные варианты, можно однократно искать заданное слово (рис. 2.25):
(рис 2.25) Поиск слова в тексте
Многие пользователи предпочитают работать по большей части с клавиатурой и прибегать к помощи мыши только там, где без нее нельзя обойтись. При работе с формой Find было бы удобно ввести слово в текстовое поле, затем, нажав клавишу Tab и Enter, осуществить поиск, — или, дважды нажав клавишу Tab, переключить фокус ввода на чекбокс Match Case. Для этого в режиме дизайна формы Find следует установить свойство TabIndex элементов управления в виде последовательной нумерации, начиная с нуля:
| Элемент управления | TabIndex |
|---|---|
| TxtFind | 0 |
| BtnOK | 1 |
| CbMatchCase | 2 |
| CbMatchWhole | 3 |
| BtnCancel | 4 |
При такой нумерации фокус ввода будет последовательно переходить в порядке возрастания — от элемента txtFind до btnCancel. Свойство TabIndex имеет особенно большое значение при создании ряда текстовых полей, где пользователю будет предлагаться ввести информацию.
Программы, как правило, содержат пункт главного меню "О программе", где в отдельном окне помещается логотип компании, лицензионное соглашение, гиперссылки на сайт разработчика и другая информация. Создадим подобную форму, используя новые элементы управления — Label, LinkLabel и PictureBox.
Итак, добавим в наш проект новую форму и назовем ее About.cs. Установим следующие свойства формы:
| About, форма, свойство | Значение |
|---|---|
| Name | About |
| FormBorderStyle | FixedSingle |
| MaximizeBox | False |
| MinimizeBox | False |
| Size | 318; 214 |
| Text | About Notepad C# |
Добавим на форму элемент управления PictureBox — он представляет собой подложку, размещаемую на форме, которая может содержать в себе рисунки для отображения. В поле свойства Image щелкаем на кнопку (…) и выбираем рисунок по адресу Code\Glava2\NotepadCSharp\Icon\logo.gif. Поскольку logo.gif является анимированным рисунком, элемент PictureBox начинает воспроизводить анимацию сразу же, даже в режиме дизайна.
Из окна ToolBox перетащим на форму кнопку, Label и LinkLabel. В поле свойства Text кнопки введем OK. Элемент Label предназначен для размещения на форме надписей, которые в готовом приложении будут доступны только для чтения. В поле свойства Text введем Notepad C# 2006 All rights reserved. Элемент LinkLabel отображает текст на форме в стиле web-ссылок и обычно используется для создания навигации между формами или ссылки на сайт. В поле Text этого элемента вводим адрес гипотетического сайта — www.notepadcsharp.com. Пользователь будет переходить на сайт, нажимая на эту ссылку, поэтому реализуем переход по гиперссылке для события Click. В окне Properties щелкаем дважды на событии Click и добавляем обработчик:
private void linkLabel1_Click(object sender, System.EventArgs e)
{
//Добавляем блок для обработки исключений — по разным причинам
//пользователь может не получить доступа к ресурсу.
try
{
//Вызываем метод VisitLink, определенный ниже
VisitLink();
}
catch (Exception ex )
{
MessageBox.Show(ex +"Unable to open link that was clicked.");
}
}
//Создаем метод VisitLink
private void VisitLink()
{
// Изменяем цвет посещенной ссылки, программно
//обращаясь к свойству LinkVisited элемента LinkLabel
linkLabel1.LinkVisited = true;
//Вызываем метод Process.Start method для запуска браузера,
//установленного по умолчанию, и открытия ссылки
System.Diagnostics.Process.Start("http://www.notepadcsharp.com");
}
Кнопка OK просто будет закрывать форму:
private void button1_Click(object sender, System.EventArgs e)
{
this.Close();
}
В пункте главного меню About Programm… формы frmmain добавляем процедуру вызова формы About:
private void mnuAbout_Click(object sender, System.EventArgs e)
{
//Создаем новый экземпляр формы About
About frm = new About();
frm.Show();
}
Запускаем приложение (рис. 2.26):
(рис 2.26) Окно About Notepad C#
В приложении Notepad C# с открытой формой About без труда можно вернуться к другим пунктам меню программы или документу, т. е. форма About позволяет переключать фокус. Такое поведение дочерних форм характерно для панелей инструментов в программах и называется немодальным. Наоборот, форма, запущенная в модальном режиме, не позволит работать с приложением до тех пор, пока мы не закроем эту форму. Для открытия формы в модальном режиме используется метод ShowDialog:
private void mnuAbout_Click(object sender, System.EventArgs e)
{
//Создаем новый экземпляр формы About
About frm = new About();
frm.ShowDialog();
}
С модификаторами доступа вы сталкивались, когда изучали синтаксис языка C#. Используя их, можно определить область видимости, иначе говоря, уровень доступности типов и членов классов, — под этим понимается участок кода, из любой точки которого будет доступен запрашиваемый тип или член класса. Технология
| Модификатор | Определение |
|---|---|
| public (общественный, открытый) | Объект доступен любому коду из любой сборки |
| private (частный, закрытый) | Объект может быть вызван другими методами только из того же типа |
| internal (внутренний, сборочный) | Объект может быть вызван любым кодом из той же сборки |
| protected (защищенный, родовой) | Объект может быть вызван производными типами независимо от их сборки |
| protected internal (родовой сборочный) | Объект может быть вызван производными типами, определенными в той же самой сборке |
В качестве объекта могут выступать методы, свойства, классы и, как мы далее увидим, — формы. Под сборкой здесь понимается функциональная единица кода (строгое определение сборок см. в лекции 9).
Наследование классов — достаточно простое и чрезвычайно удобное понятие синтаксиса С#. Формы, которые содержат большую часть методов и свойств, определенных как public, тоже можно наследовать — для получения доступа к свойствам, определенным как protected, и для ускорения работы. В самом деле, если у нас имеется уже готовая форма (например, About Notepad C#), которую мы собираемся использовать в нескольких приложениях, удобно просто создать наследуемую форму.
Запускаем приложение Notepad C# и в окне Solution Explorer щелкаем правой кнопкой на названии проекта. В появившемся контекстном меню выбираем Add\Add Inherited Form… . В окне Add New Item задаем название формы — IAbout.cs. Далее появляется окно Inheritance Picker, в котором отображаются все формы текущего проекта (рис. 2.27).
(рис 2.27) Окно выбора формы для наследования Inheritance PickerВ этом окне мы выбираем форму About. Обратите внимание на кнопку Browse, позволяющую искать формы для наследования в библиотеках dll. Нажимаем кнопку OK — в проекте появилась новая форма, содержащая все элементы управления формы About (рис. 2.28). Для завершения связей необходимо скомпилировать проект cнова — выбрав пункт главного меню Build/
(рис 2.28) Форма IAbout, наследованная от формы AboutПри редактировании родительской формы изменения также касаются дочерней — добавьте, например, кнопку на форму About, и она появится на форме IAbout. Изменения же, производимые с дочерней формой, не затрагивают родительскую форму.
Панели инструментов ToolBar содержат наборы кнопок, как правило, дублирующих пункты главного меню. В графических программах панели инструментов — основное средство работы. Откроем снова приложение Notepad C# и перетащим из окна ToolBox элемент управления ToolBar. На кнопках панели обычно располагаются иконки, поэтому, прежде чем мы начнем заниматься ими, нам следует подумать о рисунках. Добавим на форму элемент управления ImageList, применяемый для хранения рисунков, которые могут быть использованы для оформления приложения. Щелкнем в поле Images элемента ImageList (рис. 2.29).
(рис 2.29) Cвойство Images элемента ImageListДобавим файлы иконок, последовательно нажимая кнопку Add и выбирая директорию — Code\Glava2\NotepadCSharp\Icon. Мы создадим кнопки панели инструментов, дублирующие действия пунктов меню New, Open, Save, Cut, Copy и Paste, поэтому вы можете выбрать подходящие изображения на своем ImageCollectionEditor, нажимая OK. Займемся теперь элементом ToolBar. Свойству Name установим значение toolBarMain, а в поле свойства ImageList выберем imageList1. Запустим редактор ToolBarButton Collection Editor для
(рис 2.30) Редактор ToolBarButton Collection EditorДля добавления кнопок в этом редакторе тоже следует нажимать клавишу Add. Создадим шесть кнопок, установив для них следующие свойства:
| Name | Image Index | ToolTipText |
|---|---|---|
| tbNew | ![]() |
Create New |
| tbOpen | ![]() |
Open |
| tbSave | ![]() |
Save |
| tbCut | ![]() |
Cut |
| tbCopy | ![]() |
Copy |
| tbPaste | ![]() |
Paste |
Свойство Name устанавливает название кнопки для обращения к ней в коде. Свойство Image Index определяет изображение на кнопке, а в поле ToolTipText вводим текст всплывающей подсказки, которая будет появляться при наведении курсора на кнопку. Завершив работу с редактором кнопок в режиме дизайна формы frmmain, дважды щелкаем на ToolBar и переходим в код. Для создания функциональности кнопок связываем событие Click заданной кнопки c соответствующим обработчиком пунктов меню:
private void toolBarMain_ButtonClick(object sender, System.Windows.Forms.ToolBarButtonClickEventArgs e)
{
//New
if (e.Button.Equals(tbNew))
{
mnuNew_Click(this, new EventArgs());
}
//Open
if (e.Button.Equals(tbOpen))
{
mnuOpen_Click(this, new EventArgs());
}
//Save
if (e.Button.Equals(tbSave))
{
mnuSave_Click(this, new EventArgs());
}
//Cut
if (e.Button.Equals(tbCut))
{
mnuCut_Click(this, new EventArgs());
}
//Copy
if (e.Button.Equals(tbCopy))
{
mnuCopy_Click(this, new EventArgs());
}
//Paste
if (e.Button.Equals(tbPaste))
{
mnuPaste_Click(this, new EventArgs());
}
}
Запускаем приложение. Кнопки панели инструментов дублируют пункты меню, а при наведении на них появляются подсказки (рис. 2.31).
(рис 2.31) Панель инструментов ToolbarНа диске, прилагаемом к книге, вы найдете приложение NotepadCSharp (Code\Glava2\NotepadCSharp). В конце этой лекции приводится листинг форм frmamin и blank.
При изучении синтаксиса языка С# вы сталкивались с чтением и записью файлов. Если при рассмотрении обработчиков OpenFileDialog и SaveFileDialog вы не до конца поняли, как .NET Framework работает с файлами, давайте еще раз разберемся с этим понятием.
Файл — это совокупность данных, сохраненных на диске под общим названием. Когда мы открываем файл, он становится потоком, с которым мы можем осуществлять следующие операции:
В С# все классы, которые представляют потоки, наследуются от абстрактного класса Stream. Класс Stream вместе со своими подклассами обеспечивает универсальное представление источников данных и архивов, абстрагированное от подробностей операционной системы. Классы потоков определены в пространстве имен System.IO.
Для чтения и записи файлов, содержащих только текст, используются классы StreamReader и StreamWriter. Класс Stream Reader наследуется от класса TextReader, который считывает строки из стандартного текстового файла. Класс StreamWriter наследуется от класса TextWriter, записывающего символы в поток в специальном кодировании.
Создайте новое консольное приложение и назовите его FileStream. Скомпилируйте приложение (Ctrl+F5). В папке проекта создайте текстовый документ 1.txt. Откройте его в блокноте (или в приложении Notepad C#) и напишите в нем любой текст на русском и английском языках, сохранив затем его в кодировке Unicode. Выведем теперь записанный текст в окно консольного приложения. Переходим в код FileStream и подключаем пространство имен:
using System.IO;
В методе Main добавляем код:
[STAThread]
static void Main(string[] args)
{
//Cоздаем экземпляр Chitat класса StreamReader и указываем путь к файлу
и его название
StreamReader Chitat = new StreamReader("1.txt");
// Объявляем переменную A.
string A;
//В переменную А считываем содержимое файла
A = Chitat.ReadToEnd();
//Закрываем поток
Chitat.Close();
//Выводим переменную A в окно консольного приложения.
Console.WriteLine(A);
}
Когда вы работаете с файлом, например, редактируете документ Microsoft Word, вы не сможете удалить его или переместить — потому что приложение занято и поток открыт. Только завершив работу с документом и, следовательно, закрыв поток, можно перемещать его или открывать с помощью других приложений. Аналогично, в этом примере мы закрываем поток, вызывая метод Close, освобождая тем самым задействованные системные ресурсы.
Запускаем приложение. В консольном окне появляется текст, считанный из файла (рис. 2.32 ).
(рис 2.32) Чтение текста из файлаДобавим теперь объект класса StreamWriter, который будет записывать текст в файл:
[STAThread]
static void Main(string[] args)
{
//Cоздаем экземпляр Chitat класса StreamReader и указываем путь к файлу и его название
StreamReader Chitat = new StreamReader("1.txt");
// Объявляем переменную A.
string A;
//В переменную А считываем содержимое файла
A = Chitat.ReadToEnd();
//Закрываем поток
Chitat.Close();
//Выводим переменную A в окно консольного приложения.
Console.WriteLine(A);
//Cоздаем экземпляр Pisat класса StreamWriter
StreamWriter Pisat = new StreamWriter("1.txt", true, System.Text.Encoding.Unicode);
//Вызываем метод Write экземпляра Pisat
Pisat.Write("Добавляем текст");
//Закрываем поток
Pisat.Close();
// Для того, чтобы не переходить в директорию
//для просмотра файла вручную, выведем его еще раз
StreamReader ChitatSnova = new StreamReader("1.txt");
string B;
B = ChitatSnova.ReadToEnd();
ChitatSnova.Close();
Console.WriteLine(B);
}
Метод Write добавил строку в файл (рис. 2.33):
(рис 2.33) Чтение и запись текста из файлаНа диске, прилагаемом к книге, вы найдете приложение FileStream (Code\Glava2\ FileStream).
В первой лекции мы рассматривали окно Object Browser. Использование этого окна зачастую может быть гораздо более удобным, чем поиск справочной информации в MSDN.
В предыдущем примере, при создании экземпляра Pisat класса StreamWriter следует указывать параметры, передаваемые классу, — при использовании Intel Sense всплывающая подсказка указывает, какие именно параметры следует передавать (рис. 2.34).
(рис 2.34) Группа из семи различных вариантов, предлагаемых Intel Sense. Для перемещения между вариантами щелкаем на кнопку со стрелкой — вариант 1 of 7Следуя подсказке, мы могли указать и передать такие параметры:
StreamWriter Pisat = new StreamWriter("1.txt");
В этом случае файл 1.txt перезаписывался и текстовая строка помещалась в пустой файл. Для добавления в файл нужно указывать булевскую переменную:
StreamWriter Pisat = new StreamWriter("1.txt", true);
В этом случае можно было бы добавлять в файл текст, содержащий только латинские буквы. Для корректной записи кириллицы следует указывать кодировку, например Unicode, что мы и сделали:
StreamWriter Pisat = new StreamWriter("1.txt", true, System.Text.Encoding.Unicode);
Возможны и другие варианты передаваемых параметров — например, указание размера передаваемого буфера в байтах.
Предположим, мы не знаем, какую именно кодировку следует указывать. В самом деле, Intel Sense на рис. 2 не указывает, что именно кодировка Unicode принадлежит пространству имен System.Text.Encoding. Но мы можем просмотреть все доступные объекты и свойства этого пространства, используя окно Object Browser (рис. 2.35).
(рис 2.35) Пространство имен System.Text.Encoding в окне Object BrowserВ части окна Members отображаются и другие доступные кодировки, например, ASCII.
При редактировании файла требуется определять его наличие на жестком диске для выбора потом варианта сохранения — целиком или только внесенных изменений. Создайте новое консольное приложение и назовите его FileExists. Следующий код демонстрирует проверку файла на диске:
using System.IO;
…
[STAThread]
static void Main(string[] args)
{
//Выводим сообщение
Console.WriteLine("Ведите название файла");
// Создаем переменную nazvaniefayla, в которую
//запишем название файла, введеное пользователем.
string nazvaniefayla = Console.ReadLine();
//Проверяем наличие файла (в директории bin/Debug)
if (File.Exists(nazvaniefayla))
{
//Если файл существует, выводим его в консольное окно.
StreamReader chitat = new StreamReader(nazvaniefayla);
string A;
A = chitat.ReadToEnd();
chitat.Close();
Console.WriteLine(A);
}
else
{
//Если файл не найден, выводим окно сообщения
Сonsole.WriteLine("Файл с указанным именем не существует. Сoздать его Y/N");
//Считываем результат пользователя
string rezultatvibora = Console.ReadLine();
if ((rezultatvibora=="Y")||(rezultatvibora=="y"))
{
//Создаем новый файл.
StreamWriter pisat = new StreamWriter(nazvaniefayla);
Console.WriteLine("Введите текст");
string vvedemtext = Console.ReadLine();
pisat.WriteLine(vvedemtext);
pisat.Close();
Console.WriteLine("Файл создан");
}
else
{
// Если пользователь отказался от создания файла, выводим сообщение.
Console.WriteLine("Ничего не будет созданно");
}
}
}
На диске, прилагаемом к книге, вы найдете приложение FileExists (Code\Glava2\FileExists).
В рассмотренном выше примере мы проверяли наличие файла в папке Bin/Debug, где находится само приложение. В практических случаях подобная директория не может нас устраивать — требуется просматривать заданные каталоги и папки. В C# можно работать с файлами и каталогами, используя классы DirectoryInfo и FileInfo, предоставляющие всю информацию о файлах и папках.
Класс DirectoryInfo обычно применяется для таких операций, как копирование, перемещение, переименование, создание и удаление папок. Этот класс содержит метод GetFiles(), который возвращает список файлов из текущего каталога.
Класс FileInfo предоставляет методы для создания, копирования, удаления, перемещения и открытия файлов, а также является вспомогательным классом при создании объекта FileStream.
Cоздайте новое консольное приложение и назовите его DirectoryInfo. Следующий простой код выводит список всех файлов, содержащихся на диске С:
using System;
using System.IO;
namespace DirectoryInformation
{
class Class1
{
[STAThread]
static void Main(string[] args)
{
//Создаем экземпляр di класса DirectoryInfo и указываем диск С в качестве директории
DirectoryInfo directoriya = new DirectoryInfo("C:\\");
// Получаем список всех папок, содержащихся на диске С:\
DirectoryInfo[] poddirectoriya = directoriya.GetDirectories();
foreach (DirectoryInfo dd in poddirectoriya)
{
//Проверяем наличие доступа к каталогу
if(dd.Attributes == FileAttributes.Directory)
{
// Получаем список всех файлов из каталога
FileInfo[] spisokfile= dd.GetFiles();
foreach (FileInfo fi in spisokfile)
{
//Выводим список файлов
Console.WriteLine(fi.ToString());
}
}
}
}
}
}
На диске, прилагаемом к книге, вы найдете приложение DirectoryInfo — Code\Glava2\DirectoryInfo.
Для более общего способа чтения и записи файлов используются классы BinaryReader и BinaryWriter, предназначенные для чтения двоичных данных. Любой файл в конечном итоге представляет собой набор двоичных данных, следовательно, эти данные можно считывать и записывать во внутреннем, двоичном формате. Класс BinaryWriter представляет собой оболочку для байтового потока, управляющей записью двоичных данных. Класс BinaryReader является оболочкой, содержащей байтовый поток, и выполняет чтение двоичных данных.
Рассмотрим приложение, позволяющее считывать файл формата MP3 и записывать фрагмент этого файла. Создайте новое консольное приложение и назовите его BinaryReadWrite. В папку bin/Debug поместите любой музыкальный файл формата MP3, имеющийся на вашем компьютере.
Подключаем пространство имен:
using System.IO;
Добавляем код:
[STAThread]
static void Main(string[] args)
{
//Добавляем блок обработки исключений
try
{
//Создаем новый поток Chtenie и указываем файл для чтения — music.mp3
FileStream Chtenie = new FileStream("music.mp3", FileMode.Open);
//Создаем экземпляр br класса BinaryReader и
//связываем его с потоком Chtenie
BinaryReader br = new BinaryReader(Chtenie);
// Создаем массив типа байтов и
//передаем ему размер в байтах – (например, 1000000) записываемого файла
byte[] n = br.ReadBytes(1000000);
//Закрываем поток
br.Close();
//Создаем новый поток Zapis и указываем название
//файла для записи sozdanajamuzika.mp3
FileStream Zapis = new FileStream("newmusic.mp3", FileMode.CreateNew, FileAccess.Write);
//Создаем экземпляр wr класса BinaryWriter и
//связываем его с потоком Zapis
BinaryWriter wr = new BinaryWriter(Zapis);
// Можно связывать объект wr с потоком создавая его без названия:
//BinaryWriter wr = new BinaryWriter(new FileStream("sozdanajamuzika.mp3", //FileMode.CreateNew, FileAccess.Write));
//Передаем в поток массив байтов n
wr.Write(n);
//Закрываем поток
br.Close();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
Запускаем приложение. Если все сработает без ошибок — на экране появится станадртное сообщение Press any key to continue, в противном случае — поскольку мы включили блок исключений — выйдет диагностическое сообщение. Перейдем в папку bin/Debug. В ней появился файл newmusic.mp3, прослушать который мы можем с помощью любого музыкального проигрывателя.
Рассмотрим перечисления в конструкторах FileStream. Параметр FileMode определяет, каким образом открывается файл (рис. 2.36):
(рис 2.36) Перечисления FileModeЗначения перечисления FileMode указаны в таблице 2.4.
| Значение | Описание |
|---|---|
| Append | Если файл существует, он открывается, если нет — создается новый. Данные добавляются в конец файла |
| Create | Создается новый выходной файл; если файл с таким названием существует, он перезаписывается |
| Создается новый выходной файл; если файл с таким названием уже существует, генерируется исключение IOException | |
| Open | Открывается существующий файл; если файла с таким названием не существует, генерируется исключение FileNotFoundException |
| OpenOrCreate | Открывается существующий файл; если файл не существует, он создается |
| Truncate | Открывается существующий файл, но его длина усекается до нуля |
Параметр FileAccess определяет для пользователя разрешение на доступ к файлу (рис. 2.37):
(рис 2.37) Перечисления FileAccessЗначения перечисления FileAccess указаны в таблице 2.5.
| Значение | Описание |
|---|---|
| Read | Доступ на чтение из файла |
| ReadWrite | Разрешается чтение из файла и |
| Write | Доступ для записи в файл |
Дополнительно для управления режимом доступа при одновременной работе с файлами нескольких потоков используется перечисление FileShare (рис. 2.38). Например, при создании потока для чтения файла мы могли полностью определить все параметры следующим образом:
FileStream Chtenie = new FileStream("music.mp3", FileMode.Open,
FileAccess.Read, FileShare.Read);
(рис 2.38) Перечисления FileShareЗначения перечисления FileShare указаны в таблице 2.6.
| Значение | Описание |
|---|---|
| Inheritable | Дает доступ к файлам, образованных текущим потоком |
| None | Запрещает совместное использование текущего файла. Пока файл открыт, доступ к нему будет блокирован |
| Read | Позволяет открывать текущей файл для чтения |
| ReadWrite | Позволяет открывать текущий файл для чтения или записи |
| Write | Позволяет открывать текущий файл для записи |
На диске, прилагаемом к книге, вы найдете приложение BinaryReadWrite (Code\Glava2\ BinaryReadWrite).
Иногда в приложениях требуется запускать программы, входящие в состав операционной системы или установленные на данном компьютере. Создайте новое Windows-приложение и назовите его RunProgramm. На появившейся форме расположите три кнопки:
| button1, Свойства | Значения свойств |
|---|---|
| Name | btnSystemInfo |
| Size | 168;23 |
| Text | Информация о системе |
| button2, Свойства | Значения свойств |
|---|---|
| Name | btnRegEdit |
| Size | 168;23 |
| Text | Редактор реестра |
| button3, Свойства | Значения свойств |
|---|---|
| Name | btnExplorer |
| Size | 168;23 |
| Text | Проводник |
Располагаем кнопки в центре формы и выравниваем их, используя пункт меню Format. В коде формы подключаем пространство имен Diagnostics, позволяющее запускать приложения:
using System.Diagnostics;
Добавляем обработчики кнопок:
private void btnSystemInfo_Click(object sender, System.EventArgs e)
{
//Добавляем блок обработки исключений — по разным причинам (например,
//система установлена на другом диске) приложение может быть недоступным.
try
{
//Создаем новый экземпляр SysInfo класса Process
Process SysInfo = new Process();
// Если приложение не будет работать корректно — вызываем диалоговое окно ошибок.
SysInfo.StartInfo.ErrorDialog = true;
//Указываем путь к запускаемому приложению "Сведения о системе"
SysInfo.StartInfo.FileName = "C:\\Program Files\\Common Files\\Microsoft Shared\\MSInfo\\msinfo32.exe";
//Запускаем SysInfo
SysInfo.Start();
}
catch (Exception ex)
{
MessageBox.Show (ex.Message);
}
}
private void btnRegEdit_Click(object sender, System.EventArgs e)
{
try
{
Process RegEdit = new Process();
RegEdit.StartInfo.ErrorDialog = true;
//Указываем путь к запускаемому приложению "Редактор реестра"
RegEdit.StartInfo.FileName = "C:\\Windows\\regedit.exe";
RegEdit.Start();
}
catch (Exception ex)
{
MessageBox.Show (ex.Message);
}
}
private void btnExplorer_Click(object sender, System.EventArgs e)
{
try
{
Process Explorer = new Process();
Explorer.StartInfo.ErrorDialog = true;
//Указываем путь к запускаемому приложению "Проводник"
Explorer.StartInfo.FileName = "C:\\Windows\\explorer.exe";
Explorer.Start();
}
catch (Exception ex)
{
MessageBox.Show (ex.Message);
}
}
Запускаем приложение. При нажатии на кнопки запускаются соответствующие приложения (рис. 2.39).
(рис 2.39) Запуск программ из приложения RunProgrammДля запуска других программ или отдельных исполняемых файлов вашего приложения следует указывать их название и адрес, по которому они будут отыскиваться на клиентском компьютере.
На диске, прилагаемом к книге, вы найдете приложение RunProgramm (Code\Glava2\RunProgramm).
using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.IO;
namespace NotepadCSharp
{
public class frmmain : System.Windows.Forms.Form
{
private System.Windows.Forms.MainMenu mainMenu1;
private System.Windows.Forms.MenuItem menuItem5;
private System.Windows.Forms.MenuItem menuItem12;
private System.Windows.Forms.MenuItem mnuFile;
private System.Windows.Forms.MenuItem mnuNew;
private System.Windows.Forms.MenuItem mnuOpen;
private System.Windows.Forms.MenuItem mnuSave;
private System.Windows.Forms.MenuItem mnuExit;
private System.Windows.Forms.MenuItem mnuEdit;
private System.Windows.Forms.OpenFileDialog openFileDialog1;
private System.Windows.Forms.MenuItem mnuCut;
private System.Windows.Forms.MenuItem mnuCopy;
private System.Windows.Forms.MenuItem mnuPaste;
private System.Windows.Forms.MenuItem mnuDelete;
private System.Windows.Forms.MenuItem mnuSelectAll;
private System.Windows.Forms.MenuItem mnuHelp;
private System.Windows.Forms.MenuItem mnuAbout;
private System.Windows.Forms.MenuItem mnuArrangeIcons;
private System.Windows.Forms.MenuItem mnuCascade;
private System.Windows.Forms.MenuItem mnuTileHorizontal;
private System.Windows.Forms.MenuItem mnuTileVertical;
private System.Windows.Forms.MenuItem mnuWindow;
private int openDocuments = 0;
private System.Windows.Forms.MenuItem mnuFormat;
private System.Windows.Forms.SaveFileDialog saveFileDialog1;
private System.Windows.Forms.MenuItem mnuSaveAs;
private System.Windows.Forms.FontDialog fontDialog1;
private System.Windows.Forms.MenuItem mnuFont;
private System.Windows.Forms.MenuItem mnuColor;
private System.Windows.Forms.ColorDialog colorDialog1;
private System.Windows.Forms.MenuItem menuItem1;
private System.Windows.Forms.MenuItem mnuFind;
private System.Windows.Forms.ToolBarButton tbNew;
private System.Windows.Forms.ToolBarButton tbOpen;
private System.Windows.Forms.ToolBarButton tbSave;
private System.Windows.Forms.ToolBarButton tbCut;
private System.Windows.Forms.ToolBarButton tbCopy;
private System.Windows.Forms.ToolBarButton tbPaste;
private System.Windows.Forms.ImageList imageList1;
private System.Windows.Forms.ToolBar toolBarMain;
private System.ComponentModel.IContainer components;
public frmmain()
{
//
// Required for Windows Form Designer support
//
InitializeComponent();
mnuSave.Enabled = false;
//
// 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
[STAThread]
static void Main()
{
Application.Run(new frmmain());
}
private void mnuNew_Click(object sender, System.EventArgs e)
{
//Создаем новый экземпляр формы frm
blank frm = new blank();
frm.DocName = "Untitled " + ++openDocuments;
//Указываем, что родительским контейнером
//нового экземпляра будет эта, главная форма.
frm.MdiParent = this;
frm.Text = frm.DocName;
//Вызываем форму
frm.Show();
}
private void mnuArrangeIcons_Click(object sender, System.EventArgs e)
{
this.LayoutMdi(MdiLayout.ArrangeIcons);
}
private void mnuCascade_Click(object sender, System.EventArgs e)
{
this.LayoutMdi(MdiLayout.Cascade);
}
private void mnuTileHorizontal_Click(object sender, System.EventArgs e)
{
this.LayoutMdi(MdiLayout.TileHorizontal);
}
private void mnuTileVertical_Click(object sender, System.EventArgs e)
{
this.LayoutMdi(MdiLayout.TileVertical);
}
private void mnuCut_Click(object sender, System.EventArgs e)
{
blank frm = (blank)this.ActiveMdiChild;
frm.Cut();
}
private void mnuCopy_Click(object sender, System.EventArgs e)
{
blank frm = (blank)this.ActiveMdiChild;
frm.Copy();
}
private void mnuPaste_Click(object sender, System.EventArgs e)
{
blank frm = (blank)this.ActiveMdiChild;
frm.Paste();
}
private void mnuDelete_Click(object sender, System.EventArgs e)
{
blank frm = (blank)this.ActiveMdiChild;
frm.Delete();
}
private void mnuSelectAll_Click(object sender, System.EventArgs e)
{
blank frm = (blank)this.ActiveMdiChild;
frm.SelectAll();
}
private void mnuOpen_Click(object sender, System.EventArgs e)
{
//Можно программно задавать доступные для обзора расширения файлов.
//openFileDialog1.Filter = "Text Files (*.txt)|*.txt|All Files(*.*)|*.*";
//Если выбран диалог открытия файла, выполняем условие
if (openFileDialog1.ShowDialog() == DialogResult.OK)
{
//Создаем новый документ
blank frm = new blank();
//Вызываем метод Open формы blank
frm.Open(openFileDialog1.FileName);
//Указываем, что родительской формой является форма frmmain
frm.MdiParent = this;
//Присваиваем переменной DocName имя открываемого файла
frm.DocName = openFileDialog1.FileName;
//Свойству Text формы присваиваем переменную DocName
frm.Text = frm.DocName;
//Вызываем форму frm
frm.Show();
mnuSave.Enabled = true;
}
}
private void mnuSave_Click(object sender, System.EventArgs e)
{
//Переключаем фокус на данную форму.
blank frm = (blank)this.ActiveMdiChild;
//Вызываем метод Save формы blank
frm.Save(frm.DocName);
frm.IsSaved = true;
}
private void mnuSaveAs_Click(object sender, System.EventArgs e)
{
mnuSave.Enabled = true;
//Можно программно задавать доступные для обзора расширения файлов
//openFileDialog1.Filter = "Text Files (*.txt)|*.txt|All Files(*.*)|*.*";
//Если выбран диалог открытия файла, выполняем условие
if (saveFileDialog1.ShowDialog() == DialogResult.OK)
{
//Переключаем фокус на данную форму.
blank frm = (blank)this.ActiveMdiChild;
//Вызываем метод Save формы blank
frm.Save(saveFileDialog1.FileName);
//Указываем, что родительской формой является форма frmmain
frm.MdiParent = this;
//Присваиваем переменной FileName имя сохраняемого файла
frm.DocName = saveFileDialog1.FileName;
//Свойству Text формы присваиваем переменную DocName
frm.Text = frm.DocName;
frm.IsSaved = true;
}
}
private void mnuExit_Click(object sender, System.EventArgs e)
{
this.Close();
}
private void mnuFont_Click(object sender, System.EventArgs e)
{
//Переключаем фокус на данную форму.
blank frm = (blank)this.ActiveMdiChild;
//Указываем, что родительской формой является форма frmmain
frm.MdiParent = this;
//Вызываем диалог
fontDialog1.ShowColor = true;
//Связываем свойства SelectionFont и SelectionColor элемента RichTextBox
//с соответствующими свойствами диалога
fontDialog1.Font = frm.richTextBox1.SelectionFont;
fontDialog1.Color = frm.richTextBox1.SelectionColor;
//Если выбран диалог открытия файла, выполняем условие
if (fontDialog1.ShowDialog() == DialogResult.OK)
{
frm.richTextBox1.SelectionFont = fontDialog1.Font;
frm.richTextBox1.SelectionColor = fontDialog1.Color;
}
//Показываем форму
frm.Show();
}
private void mnuColor_Click(object sender, System.EventArgs e)
{
blank frm = (blank)this.ActiveMdiChild;
frm.MdiParent = this;
colorDialog1.Color = frm.richTextBox1.SelectionColor;
if (colorDialog1.ShowDialog() == DialogResult.OK)
{
frm.richTextBox1.SelectionColor = colorDialog1.Color;
}
frm.Show();
}
private void mnuFind_Click(object sender, System.EventArgs e)
{
//Создаем новый экземпляр формы FindForm
FindForm frm = new FindForm();
//Если выбран результат DialogResult.Cancel, закрываем форму (до этого
//мы использовали DialogResult.OK
if(frm.ShowDialog(this) == DialogResult.Cancel) return;
////Переключаем фокус на данную форму.
blank form = (blank)this.ActiveMdiChild;
////Указываем, что родительской формой является форма frmmain
form.MdiParent = this;
//Вводим переменную для поиска в определенной части текста —
//поиск слова будет осуществляться от текущей позиции курсора
int start = form.richTextBox1.SelectionStart;
//Вызываем предопределенный метод Find элемента richTextBox1.
form.richTextBox1.Find(frm.FindText, start, frm.FindCondition);
}
private void mnuAbout_Click(object sender, System.EventArgs e)
{
//Создаем новый экземпляр формы About
About frm = new About();
frm.Show();
}
private void toolBarMain_ButtonClick(object sender, System.Windows.Forms.ToolBarButtonClickEventArgs e)
{
//New
if (e.Button.Equals(tbNew))
{
mnuNew_Click(this, new EventArgs());
}
//Open
if (e.Button.Equals(tbOpen))
{
mnuOpen_Click(this, new EventArgs());
}
//Save
if (e.Button.Equals(tbSave))
{
mnuSave_Click(this, new EventArgs());
}
//Cut
if (e.Button.Equals(tbCut))
{
mnuCut_Click(this, new EventArgs());
}
//Copy
if (e.Button.Equals(tbCopy))
{
mnuCopy_Click(this, new EventArgs());
}
//Paste
if (e.Button.Equals(tbPaste))
{
mnuPaste_Click(this, new EventArgs());
}
}
}
}
using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.IO;
namespace NotepadCSharp
{
/// <summary>
/// Summary description for blank.
/// </summary>
public class blank : System.Windows.Forms.Form
{
public System.Windows.Forms.RichTextBox richTextBox1;
public string DocName = "";
private string BufferText = "";
private System.Windows.Forms.ContextMenu contextMenu1;
private System.Windows.Forms.MenuItem cmnuCut;
private System.Windows.Forms.MenuItem cmnuCopy;
private System.Windows.Forms.MenuItem cmnuPaste;
private System.Windows.Forms.MenuItem cmnuDelete;
private System.Windows.Forms.MenuItem menuItem6;
private System.Windows.Forms.MenuItem cmnuSelectAll;
public bool IsSaved = false;
private System.Windows.Forms.StatusBar statusBar1;
private System.Windows.Forms.StatusBarPanel sbAmount;
private System.Windows.Forms.StatusBarPanel sbTime;
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.Container components = null;
public blank()
{
InitializeComponent();
//Свойству Text панели sbTime устанавливаем системное время,
// конвертировав его в тип String
sbTime.Text = Convert.ToString(System.DateTime.Now.ToLongTimeString());
//В тексте всплывающей подсказки выводим текущую дату
sbTime.ToolTipText = Convert.ToString(System.DateTime.Today.ToLongDateString());
}
protected override void Dispose( bool disposing )
{
if( disposing )
{
if(components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}
region Windows Form Designer generated code
// Вырезание текста
public void Cut()
{
this.BufferText = richTextBox1.SelectedText;
richTextBox1.SelectedText = "";
}
// Копирование текста
public void Copy()
{
this.BufferText = richTextBox1.SelectedText;
}
// Вставка
public void Paste()
{
richTextBox1.SelectedText = this.BufferText;
}
// Выделение всего текста — используем свойство SelectAll элемента управления RichTextBox
public void SelectAll()
{
richTextBox1.SelectAll();
}
// Удаление.
public void Delete()
{
richTextBox1.SelectedText = "";
this.BufferText = "";
}
//Создаем метод Open, в качестве параметра объявляем строку адреса файла.
public void Open(string OpenFileName)
{
//Если файл не выбран, возвращаемся назад (появится встроенное предупреждение)
if (OpenFileName == "")
{
return;
}
else
{
//Создаем новый объект StreamReader и передаем ему переменную OpenFileName
StreamReader sr = new StreamReader(OpenFileName);
//Читаем весь файл и записываем его в richTextBox1
richTextBox1.Text = sr.ReadToEnd();
// Закрываем поток
sr.Close();
//Переменной DocName присваиваем адресную строку.
DocName = OpenFileName;
}
}
private void cmnuCut_Click(object sender, System.EventArgs e)
{
Cut();
}
private void cmnuCopy_Click(object sender, System.EventArgs e)
{
Copy();
}
private void cmnuPaste_Click(object sender, System.EventArgs e)
{
Paste();
}
private void cmnuDelete_Click(object sender, System.EventArgs e)
{
Delete();
}
private void cmnuSelectAll_Click(object sender, System.EventArgs e)
{
SelectAll();
}
//Создаем метод Save, в качестве параметра объявляем строку адреса файла.
public void Save(string SaveFileName)
{
//Если файл не выбран, возвращаемся назад (появится встроенное предупреждение)
if (SaveFileName == "")
{
return;
}
else
{
//Создаем новый объект StreamWriter и передаем ему переменную OpenFileName
StreamWriter sw = new StreamWriter(SaveFileName);
//Содержимое richTextBox1 записываем в файл
sw.WriteLine(richTextBox1.Text);
//Закрываем поток
sw.Close();
//Устанавливаем в качестве имени документа название сохраненного файла
DocName = SaveFileName;
}
}
private void blank_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
//Если переменная IsSaved имеет значение true, т. е. документ новый документ
//был сохранен (Save As) или в открытом документе были сохранены изменения (Save), то выполняется условие
if(IsSaved ==true)
//Появляется диалоговое окно, предлагающее сохранить документ.
if (MessageBox.Show("Do you want save changes in " + this.DocName + "?",
"Message", MessageBoxButtons.YesNo,
MessageBoxIcon.Question) == DialogResult.Yes)
//Если была нажата кнопка Yes, вызываем метод Save
{
this.Save(this.DocName);
}
}
private void richTextBox1_TextChanged(object sender, System.EventArgs e)
{
//Свойству Text панели sbAmount устанавливаем надпись "Аmount of symbols "
//и длину текста в RichTextBox.
sbAmount.Text = "Аmount of symbols " + richTextBox1.Text.Length.ToString();
}
}
}
Элементы управления — это компоненты, обеспечивающие взаимодействие между пользователем и программой. Среда Visual Studio.NET предоставляет большое количество элементов, которые можно сгруппировать по нескольким функциональным группам.
Группа командных объектов
Элементы управления Button, LinkLabel, ToolBar реагируют на нажатие кнопки мыши и немедленно запускают какое-либо действие. Наиболее распространенная группа элементов.
Группа текстовых объектов
Большинство приложений предоставляют возможность пользователю вводить текст и, в свою
Группа переключателей
Приложение может содержать несколько предопределенных вариантов выполнения действия или задачи; элементы управления этой группы предоставляют возможность выбора пользователю. Это одна из самых обширных групп элементов, в которую входят ComboBox, ListBox, ListView, TreeView, NumericUpDown и многие другие.
Группа контейнеров
С элементами этой группы действия приложения практически никогда не связываются, но они имеют большое значение для организации других элементов управления, их группировки и общего дизайна формы. Как правило, элементы этой группы, расположенные на форме, служат подложкой кнопкам, текстовым полям, спискам — поэтому они и называются контейнерами. Элементы Panel,
Группа графических элементов
Даже самое простое приложение Windows содержит графику — иконки, заставку, встроенные изображения. Для размещения и отображения их на форме используются элементы для работы с графикой — Image List, Picture Box.
Диалоговые окна
Выполняя различные операции с документом — открытие, сохранение, печать, предварительный просмотр, — мы сталкиваемся с соответствующими диалоговыми окнами. Разработчикам .NET не приходится заниматься созданием окон стандартных процедур: элементы OpenFileDialog, SaveFile Dialog, ColorDialog, PrintDialog содержат уже готовые операции.
Группа меню
Многие пользователи настраивают интерфейс приложений на свой вкус: одним нравится наличие определенных панелей инструментов, другим – индивидуальное расположение окон. Но в любом приложении будет присутствовать меню, содержащее в себе доступ ко всем возможностям и настройкам приложения. Элементы MainMenu, ContextMenu представляют собой готовые формы для внесения заголовков и пунктов меню.
Практическая работа с различными элементами управления будет рассмотрена в этой и последующих лекциях.
Большинство Windows-приложений оснащено главным меню, которое представляет собой иерархическую структуру выполняемых функций и команд. Практически все функции, которые можно осуществить при помощи элементов управления, имеют свой аналог в виде пункта меню.
Для создания главного меню используется элемент управления MainMenu, расположенный на панели инструментов ToolBox. Создайте новое приложение и назовите его NotepadCSharp. Установите следующие свойства формы:
| Form1, форма, свойство | Значение |
|---|---|
| Name | frmmain |
| Icon | Code\Glava2\NotepadCSharp\Icon\README.ICO |
| Text | Notepad C# |
| Maximized |
Перетаскиваем элемент управления на форму. Нам предстоит заполнить строки меню следующими пунктами (рис. 2.1):
(рис 2.1) Пункты главного меню приложения Notepad C#Каждый пункт главного меню имеет свое окно свойств, в котором, подобно другим элементам управления, задаются значения свойств Name и Text (рис. 2.2). В поле Text перед словом New стоит знак — так называемый амперсанд, указывающий, что N должно быть подчеркнута и будет частью встроенного клавиатурного интерфейса Windows. Когда пользователь на клавиатуре нажимает клавишу Alt и затем N, выводится подменю New.
(рис 2.2) Свойства пункта меню NewВ Windows есть еще интерфейс для работы с так называемыми быстрыми клавишами, или
| Name | Text | Shortcut |
|---|---|---|
| mnuFile | File | |
| mnuNew | New | CtrlN |
| mnuOpen | Open | CtrlO |
| mnuSave | Save | CtrlS |
| menuItem5 | - | |
| mnuExit | Exit | AltF4 |
| mnuEdit | Edit | |
| mnuCut | Cut | CtrlX |
| mnuCopy | Copy | CtrlC |
| mnuPaste | Paste | CtrlV |
| mnuDelete | Delete | Del |
| mnuSelectAll | SelectAll | CtrlA |
| mnuFormat | Format | |
| mnuFont | Font… | |
| mnuColor | Color… | |
| mnuWindow | Window | |
| mnuArrangeIcons | Arrange Icons | |
| mnuCascade | Cascade | |
| mnuTileHorizontal | Tile Horizontal | |
| mnuTileVertical | Tile Vertical | |
| mnuHelp | ? | |
| mnuAbout | About Programm... |
Вы можете самостоятельно выбрать сочетания клавиш, не указанные в табл. 2.1, для соответствующих пунктов меню.
Такие программы, как блокнот и

(рис 2.4) SDI приложение Microsoft Paint(рис 2.3) MDI-приложение Adobe PhotoshopВ MDI-приложениях главная форма содержит в себе несколько документов, каждый из которых является холстом в графических программах или полем для текста в редакторах. Продолжим работу над приложением Notepad C#. В окне Solution Explorer щелкаем правой кнопкой на имени проекта и в появившемся контекстном меню выбираем Add/ Add Windows Form… . В появившемся окне называем форму – blank.cs. В нашем проекте появилась новая форма — будем называть ее дочерней. В режиме дизайна перетаскиваем на нее элемент управления RichTextBox: в отличие от элемента textBox, размер содержимого текста в нем не ограничивается 64 Кб; кроме того, RichTextBox позволяет редактировать цвет текста, добавлять изображения. Свойству Dock этого элемента устанавливаем значение Fill (рис. 2.5):
(рис 2.5) Свойство Dock элемента RichTextBoxПереходим в режим дизайна формы Frmmain и устанавливаем свойству IsMdiContainer значение true. Цвет формы при этом становится темно-серым. Новые документы будут у нас появляться при нажатии пункта меню New (которому мы установили сочетание клавиш Ctrl+N), поэтому дважды щелкаем в этом пункте и переходим в код:
private void mnuNew_Click(object sender, System.EventArgs e)
{
//Создаем новый экземпляр формы frm
blank frm = new blank();
//Указываем, что родительским контейнером
//нового экземпляра будет эта, главная форма.
frm.MdiParent = this;
//Вызываем форму
frm.Show();
}
Запускаем приложение. Теперь при нажатии клавиш Ctrl+N или выборе пункта меню New появляется несколько окон, расположенных каскадом. Однако заголовок у них всех одинаковый — blank. При создании нескольких документов, например в Microsoft Word, они называются ДокументN, где N — номер документа. Переключаемся в код формы blank, и в классе blank объявляем переменную DocName:
public string DocName = "";
Переключаемся в код формы frmmain и в классе frmmain объявляем переменную openDocuments:
private int openDocuments = 0;
Присваиваем переменной DocName часть названия по шаблону, в который включен счетчик числа открываемых документов, затем это значение передаем свойству Text создаваемой формы frm:
private void mnuNew_Click(object sender, System.EventArgs e)
{
blank frm = new blank();
frm.DocName = "Untitled " + ++openDocuments;
frm.Text = frm.DocName;
frm.MdiParent = this;
frm.Show();
}
Запускаем приложение. Теперь новые документы содержат разные заголовки (рис. 2.6).
(рис 2.6) Новые документы имеют упорядоченные названия
При работе с несколькими документами в MDI-приложениях удобно упорядочивать их на экране. Можно, конечно, распределять формы вручную, но при работе с большим количеством документов это представляется затруднительным. В пункте меню Window реализуем процедуру выравнивания окон.
Создаем обработчиков:
private void mnuArrangeIcons_Click(object sender, System.EventArgs e)
{
this.LayoutMdi(MdiLayout.ArrangeIcons);
}
private void mnuCascade_Click(object sender, System.EventArgs e)
{
this.LayoutMdi(MdiLayout.Cascade);
}
private void mnuTileHorizontal_Click(object sender, System.EventArgs e)
{
this.LayoutMdi(MdiLayout.TileHorizontal);
}
private void mnuTileVertical_Click(object sender, System.EventArgs e)
{
this.LayoutMdi(MdiLayout.TileVertical);
}
Метод LayoutMdi содержит перечисление MdiLayout, содержащее четыре члена. ArrangeIcons переключает фокус на выбранную форму, в свойстве MdiList пункта меню ArrangeIcons устанавливаем также значение true. При открытии нескольких новых документов окна располагаются каскадом (рис. 2.6), их можно расположить горизонтально — значение TileHorizontal или вертикально — значение TileVertical, а затем снова вернуть каскадное расположение — Cascade (рис. 2.7):
(рис 2.7) Расположение окон TileHorizontal и пункт меню ArrangeIcons
С приложением работать будет удобней, если при создании нового документа он сразу будет занимать всю область главной формы. Для этого установим свойство blank Maximized. Теперь приступим к созданию обработчиков для стандартных операций вырезания, копирования и вставки. Элемент управления RichTextBox имеет свойство SelectedText, которое содержит выделенный фрагмент текста. На основании этого свойства и будут реализованы действия по работе с текстом. В коде формы blank объявляем переменную BufferText, в которой будет храниться буферизованный фрагмент текста:
private string BufferText = "";
Далее создаем соответствующие методы:
// Вырезание текста
public void Cut()
{
this.BufferText = richTextBox1.SelectedText;
richTextBox1.SelectedText = "";
}
// Копирование текста
public void Copy()
{
this.BufferText = richTextBox1.SelectedText;
}
// Вставка
public void Paste()
{
richTextBox1.SelectedText = this.BufferText;
}
// Выделение всего текста — используем свойство SelectAll элемента управления RichTextBox
public void SelectAll()
{
richTextBox1.SelectAll();
}
// Удаление
public void Delete()
{
richTextBox1.SelectedText = "";
this.BufferText = "";
}
Переключаемся в режим дизайна формы и создаем обработчиков для пунктов меню:
private void mnuCut_Click(object sender, System.EventArgs e)
{
blank frm = (blank)this.ActiveMdiChild;
frm.Cut();
}
private void mnuCopy_Click(object sender, System.EventArgs e)
{
blank frm = (blank)this.ActiveMdiChild;
frm.Copy();
}
private void mnuPaste_Click(object sender, System.EventArgs e)
{
blank frm = (blank)this.ActiveMdiChild;
frm.Paste();
}
private void mnuDelete_Click(object sender, System.EventArgs e)
{
blank frm = (blank)this.ActiveMdiChild;
frm.Delete();
}
private void mnuSelectAll_Click(object sender, System.EventArgs e)
{
blank frm = (blank)this.ActiveMdiChild;
frm.SelectAll();
}
Свойство ActiveMdiChild переключает фокус на текущую форму, если их открыто несколько, и вызывает один из методов, определенных в дочерней форме. Запускаем приложение. Теперь мы можем выполнять все стандартные операции с текстом.
Контекстное меню, дублирующее некоторые действия основного меню, — не самый быстрый способ работы с программой, но самый привычный для пользователя. Элемент управления TextBox содержит в себе простейшее контекстное меню, дублирующее действия подменю Edit. Для того чтобы убедиться в этом, достаточно нанести этот элемент управления на форму и запустить приложение (рис. 2.8):
(рис 2.8) Контекстное меню элемента TextBoxВ нашем приложении Notepad C# в качестве текстового элемента мы используем RichTextBox. Добавим элемент управления contextMenu из окна ToolBox на форму blank. Добавляем пункты контекстного меню точно так же, как мы это делали для главного меню (рис. 2.9):
(рис 2.9) Пункты контекстного менюСвойство Text и Shortcut пунктов меню оставляем прежними. Если мы установим затем для свойства ShowShortcut значение false, то сочетания клавиш будут работать, но в самом меню отображаться не будут — как на рис. рис. 2.8. Свойство Name будет формироваться следующим образом: для пункта Cut — cmnuCut, для Сopy — cmnuCopy и т.д.
В обработчике пунктов просто вызываем соответствующие методы:
private void cmnuCut_Click(object sender, System.EventArgs e)
{
Cut();
}
private void cmnuCopy_Click(object sender, System.EventArgs e)
{
Copy();
}
private void cmnuPaste_Click(object sender, System.EventArgs e)
{
Paste();
}
private void cmnuDelete_Click(object sender, System.EventArgs e)
{
Delete();
}
private void cmnuSelectAll_Click(object sender, System.EventArgs e)
{
SelectAll();
}
Последнее, что нам осталось сделать, — это определить, где будет появляться контекстное меню. Элемент RichTextBox, так же как и формы frmmain и blank, имеет свойство ContextMenu, где мы и указываем contextMenu1, поскольку нам нужно отображать меню именно в текстовом поле. Запускаем приложение — теперь в любой точке текста доступно меню (рис. 2.10).
(рис 2.10) Контекстное меню
Среда Visual Studio .NET содержит готовые диалоговые окна, предлагающие выбрать файл для открывания или путь на диске для сохранений текущего файла (рис. 2.11).
(рис 2.11) Диалоговое окно открытия файлаМы рассмотрим одну часть диалоговых окон в этой лекции, а другую, относящуюся к подготовке документа к печати, — в лекции 6.
Добавьте на форму frmmain элемент управления OpenFileDialog из окна панели инструментов ToolBox. Подобно элементу MainMenu, он будет располагаться на панели невидимых компонент (рис. 2.12):
(рис 2.12) Добавление OpenFileDialog на формуСвойство FileName задает название файла, которое будет находиться в поле "Имя файла:" при появлении диалога. На рис. рис. 2.12 название в этом поле — "Текстовые файлы", поскольку на рис. рис. 2.11 был введен именно этот текст. Свойство Filter задает ограничение файлов, которые могут быть выбраны для открытия — в окне будут показываться только файлы с заданным расширением. Через вертикальную разделительную линию можно задать смену типа расширения, отображаемого в выпадающем списке "Тип файлов". Здесь введено Text Files (*.txt)|*.txt|All Files(*.*)|*.* что означает обзор либо текстовых файлов, либо всех. Свойство InitialDirectory позволяет задать директорию, откуда будет начинаться обзор. Если это свойство не установлено, исходной директорией будет рабочий стол.
Для работы с файловыми потоками в коде формы blank подключаем пространство имен System.IO:
using System.IO;
В методе Open считываем содержимое файла в RichTextBox:
//Создаем метод Open, в качестве параметра объявляем строку адреса файла.
public void Open(string OpenFileName)
{
//Если файл не выбран, возвращаемся назад (появится встроенное предупреждение)
if (OpenFileName == "")
{
return;
}
else
{
//Создаем новый объект StreamReader и передаем ему переменную //OpenFileName
StreamReader sr = new StreamReader(OpenFileName);
//Читаем весь файл и записываем его в richTextBox1
richTextBox1.Text = sr.ReadToEnd();
// Закрываем поток
sr.Close();
//Переменной DocName присваиваем адресную строку
DocName = OpenFileName;
}
}
Добавим обработчик пункта меню Open формы frmmain:
private void mnuOpen_Click(object sender, System.EventArgs e)
{
//Можно программно задавать доступные для обзора расширения файлов
//openFileDialog1.Filter = "Text Files (*.txt)|*.txt|All Files(*.*)|*.*";
//Если выбран диалог открытия файла, выполняем условие
if (openFileDialog1.ShowDialog() == DialogResult.OK)
{
//Создаем новый документ
blank frm = new blank();
//Вызываем метод Open формы blank
frm.Open(openFileDialog1.FileName);
//Указываем, что родительской формой является форма frmmain
frm.MdiParent = this;
//Присваиваем переменной DocName имя открываемого файла
frm.DocName = openFileDialog1.FileName;
//Свойству Text формы присваиваем переменную DocName
frm.Text = frm.DocName;
//Вызываем форму frm
frm.Show();
}
}
Запускаем приложение и открываем текстовый файл, сохраненный в формате блокнота (рис. 2.13).
(рис 2.13) Заголовок формы представляет собой адрес и имя открытого файлаДля корректного чтения кириллицы текст в блокноте должен быть сохранен в кодировке Unicode. К сожалению, встроенные диалоговые окна OpenFileDialog Visual Studio .NET не содержат дополнительного поля, позволяющего выбирать кодировку файла при его открытии или сохранении, как это реализовано, например, в блокноте.
Для сохранения файлов добавляем на форму frmmain элемент управления saveFileDialog1. Cвойства этого диалога в точности такие же, как у OpenFileDialog (рис. 2.12). Переходим в код формы blank:
//Создаем метод Save, в качестве параметра объявляем строку адреса файла.
public void Save(string SaveFileName)
{
//Если файл не выбран, возвращаемся назад (появится встроенное предупреждение)
if (SaveFileName == "")
{
return;
}
else
{
//Создаем новый объект StreamWriter и передаем ему переменную //OpenFileName
StreamWriter sw = new StreamWriter(SaveFileName);
//Содержимое richTextBox1 записываем в файл
sw.WriteLine(richTextBox1.Text);
//Закрываем поток
sw.Close();
//Устанавливаем в качестве имени документа название сохраненного файла
DocName = SaveFileName;
}
}
Добавляем обработчик пункта меню Save формы frmmain:
private void mnuSave_Click(object sender, System.EventArgs e)
{
//Можно программно задавать доступные для обзора расширения файлов
//openFileDialog1.Filter = "Text Files (*.txt)|*.txt|All Files(*.*)|*.*";
//Если выбран диалог открытия файла, выполняем условие
if (saveFileDialog1.ShowDialog() == DialogResult.OK)
{
//Переключаем фокус на данную форму.
blank frm = (blank)this.ActiveMdiChild;
//Вызываем метод Save формы blank
frm.Save(saveFileDialog1.FileName);
//Указываем, что родительской формой является форма frmmain
frm.MdiParent = this;
//Присваиваем переменной FileName имя сохраняемого файла
frm.DocName = saveFileDialog1.FileName;
//Свойству Text формы присваиваем переменную DocName
frm.Text = frm.DocName;
}
}
Запускаем приложение. Теперь файлы можно открывать, редактировать и сохранять. Однако, при сохранении внесенных изменений в уже сохраненном файле вместо его перезаписи вновь появляется окно SaveFileDialog. Изменим нашу программу так, чтобы можно было сохранять и перезаписывать файл. В конструкторе формы frmmain после InitializeComponent отключим доступность пункта меню Save:
mnuSave.Enabled = false;
Переключаемся в режим дизайна формы frmmain и добавляем пункт меню Save As после пункта Save. Устанавливаем следующие свойства этого пункта: Name — mnuSaveAs, Shortcut — CtrlShiftS, Text Save As. В обработчике Save As вставляем вырезанный обработчик пункта Save и добавляем включение доступности Save:
mnuSave.Enabled = true;
Сохранять изменения требуется как в только что сохраненных документах, так и в документах, созданных ранее и открытых для редактирования. Поэтому добавим в метод Open включение доступности пункта меню Save:
private void mnuOpen_Click(object sender, System.EventArgs e)
{
mnuSave.Enabled = true;
}
В обработчике пункта Save добавим простую перезапись файла — вызов метода Save формы blank:
private void mnuSave_Click(object sender, System.EventArgs e)
{
//Переключаем фокус на данную форму.
blank frm = (blank)this.ActiveMdiChild;
//Вызываем метод Save формы blank
frm.Save(frm.DocName);
}
Запускаем приложение. Теперь, если мы работаем с несохраненным документом, пункт Save неактивен (рис. 2.14), после сохранения он становится активным (рис. 2.15) и, кроме того, работает сочетание клавиш Ctrl+S. Можно сохранить копию текущего документа, вновь воспользовавшись пунктом меню Save As (рис. 2.16).

(рис 2.15) Новый документ(рис 2.14) Сохраненный документ
(рис 2.16) Сохранение копииКонечно, эту задачу можно решить более элегантно — совместив оба пункта сохранения документа в один. Но мне хотелось показать разницу между простым сохранением и перезаписью файлов, кроме того, мы научились отключать доступность пунктов меню.
Всякий раз, когда мы закрываем документ Microsoft Word, в который внесли изменения, появляется окно предупреждения, предлагающее сохранить документ. Добавим аналогичную функцию в наше приложение. В классе blank : System.Windows.Forms.Form формы blank создаем переменную, которая будет фиксировать сохранение документа:
public bool IsSaved = false;
В обработчик методов Save и Save As формы frmmain добавляем изменение значения этой переменной:
private void mnuSave_Click(object sender, System.EventArgs e)
{
…
frm.IsSaved = true;
}
private void mnuSaveAs_Click(object sender, System.EventArgs e)
{
…
frm.IsSaved = true;
}
Переходим в режим дизайна формы blank и в окне свойств переключаемся на события формы, щелкнув на значок с молнией. В поле события Closing дважды щелкаем и переходим в код:
private void blank_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
//Если переменная IsSaved имеет значение true, т. е. новый документ
//был сохранен (Save As) или в открытом документе были сохранены изменения (Save), то //выполняется условие
if(IsSaved ==true)
//Появляется диалоговое окно, предлагающее сохранить документ.
if(MessageBox.Show("Do you want save changes in " + this.DocName + "?",
"Message", MessageBoxButtons.YesNo,
MessageBoxIcon.Question) == DialogResult.Yes)
//Если была нажата кнопка Yes, вызываем метод Save
{
this.Save(this.DocName);
}
}
Запускаем приложение. При закрытии формы blank или frmmain появляется окно предупреждения (рис. 2.17):
(рис 2.17) Окно предупреждения при закрытии формы
При создании MDI-приложений приходится разделять код для открытия и сохранения файлов, как мы делали для приложения Notepad C#. В случае
| TextBox, свойство | Значение |
|---|---|
| Name | txtBox |
| Dock | Fill |
| Multiline | true |
| Text | Да |
Добавляем на форму элемент MainMenu, в котором будет всего три пункта — File, Open и Save (свойства этих пунктов см. в таблице 2.1). Из окна ToolBox перетаскиваем элементы OpenFileDialog и SaveFileDialog — свойства этих элементов в точности такие же, как и у диалогов приложения Notepad C#. Переходим в код формы. Подключаем пространство имен для работы с файловыми потоками:
using System.IO;
Добавляем обработчик для пункта меню Open:
private void mnuOpen_Click(object sender, System.EventArgs e)
{
//Показываем диалог выбора файла
openFileDialog1.ShowDialog();
// Переменной fileName присваиваем имя открываемого файла
string fileName = openFileDialog1.FileName;
//Создаем поток fs и открываем файл для чтения.
FileStream filestream= File.Open(fileName, FileMode.Open, FileAccess.Read);
//Проверяем, открыт ли поток, и если открыт, выполняем условие
if(filestream != null)
{
//Создаем объект streamreader и связываем его с потоком filestream
StreamReader streamreader = new StreamReader(filestream);
//Считываем весь файл и записываем его в TextBox
txtBox.Text = streamreader.ReadToEnd();
//Закрываем поток.
filestream.Close();
}
}
Добавляем обработчик для пункта меню Save:
private void mnuSave_Click(object sender, System.EventArgs e)
{
//Показываем диалог выбора файла
saveFileDialog1.ShowDialog();
// В качестве имени сохраняемого файла устанавливаем переменную fileName
string fileName=saveFileDialog1.FileName;
//Создаем поток fs и открываем файл для записи.
FileStream filestream = File.Open(fileName, FileMode.Create, FileAccess.Write);
//Проверяем, открыт ли поток, и если открыт, выполняем условие
if(filestream != null)
{
//Создаем объект streamwriter и связываем его с потоком filestream
StreamWriter streamwriter = new StreamWriter(filestream);
//Записываем данные из TextBox в файл
streamwriter.Write(txtBox.Text);
//Переносим данные из потока в файл
streamwriter.Flush();
//Закрываем поток
filestream.Close();
}
}
Запускаем приложение. Как уже отмечалось, элемент управления TextBox имеет встроенное контекстное меню, поддерживает сочетание клавиш для редактирования, а диалоговые окна открытия и сохранения позволяют этому простейшему приложению работать с внешними файлами.
На диске, прилагаемом к книге, вы найдете приложение TextEditor (Code\Glava2\TextEditor).
Продолжим работу над приложением Notepad C#. Добавим теперь возможность выбирать шрифт, его размер и начертание. В режиме дизайна перетащим на форму frmmain из окна ToolBox элемент управления FontDialog. Не изменяя ничего в свойствах этого элемента, переходим в обработчик пункта Font главного меню:
private void mnuFont_Click(object sender, System.EventArgs e)
{
//Переключаем фокус на данную форму.
blank frm = (blank)this.ActiveMdiChild;
//Указываем, что родительской формой является форма frmmain
frm.MdiParent = this;
//Вызываем диалог
fontDialog1.ShowColor = true;
//Связываем свойства SelectionFont и SelectionColor элемента RichTextBox
//с соответствующими свойствами диалога
fontDialog1.Font = frm.richTextBox1.SelectionFont;
fontDialog1.Color = frm.richTextBox1.SelectionColor;
//Если выбран диалог открытия файла, выполняем условие
if (fontDialog1.ShowDialog() == DialogResult.OK)
{
frm.richTextBox1.SelectionFont = fontDialog1.Font;
frm.richTextBox1.SelectionColor = fontDialog1.Color;
}
//Показываем форму
frm.Show();
}
Запускаем приложение, и в окне Output появляется список ошибок (рис. 2.18).
(рис 2.18) Список ошибок — NotepadCSharp.blank.richTextBox1 недоступен из-за своего уровня защитыВ чем же дело? При расположении на форме blank элемента управления RichTextBox среда Visual Studio.NET сгенерировала экземпляр richTextBox1 класса System.Windows.Forms.RichTextBox с модификатором доступа private, из-за чего при обращении к нему и возникает исключение:
private System.Windows.Forms.RichTextBox richTextBox1;
Изменим модификатор на public и снова запустим приложение. При выборе пункта меню Font теперь можно менять параметры текущего текста.
Диалоговое окно FontDialog содержит список цветов, которые могут быть применены к тексту, но предлагаемый список ограничен. Более интересной представляется возможность назначать пользовательский цвет, который может быть определен в большом диапазоне (рис. 2.19):
(рис 2.19) Диалоговое окно ColorDialogИз окна ToolBox добавляем элемент управления ColorDialog и, вновь не изменяя его свойств, переходим к обработчику пункта Color главного меню формы frmmain:
private void mnuColor_Click(object sender, System.EventArgs e)
{
blank frm = (blank)this.ActiveMdiChild;
frm.MdiParent = this;
colorDialog1.Color = frm.richTextBox1.SelectionColor;
if (colorDialog1.ShowDialog() == DialogResult.OK)
{
frm.richTextBox1.SelectionColor = colorDialog1.Color;
}
frm.Show();
}
Обратите внимание на то, что код для ColorDialog в точности такой же, как и часть кода для свойства Color диалога FontDialog. Это и не удивительно: ведь мы связываем эти диалоги со свойствами одного и того же объекта — RichTextBox.
Элемент управления StatusBar применяется в программах для вывода информации в строку состояния — небольшую полоску, расположенную внизу приложения. В Microsoft Word, например, на ней отображается количество страниц, язык ввода, состояние проверки правописания и другие параметры. Добавим к приложению Notepad C# строку состояния, на которой осуществляется подсчет вводимых символов и выводится системное время.
Добавляем на форму blank элемент управления StatusBar. Удаляем содержимое поля свойства Text. В поле свойства Panels щелкаем на кнопку (…). Открывается StatusBarCollectionEditor, в котором мы создаем панели для отображения. Создайте две панели, дважды щелкая на кнопке Add, и установите им следующие свойства (измененные значения выделяются жирным шрифтом) (рис. 2.20 и рис. 2.21):

(рис 2.21) Свойства панели sbAmount(рис 2.20) Свойства панели sbTimeЗначения некоторых свойств панели приводятся в таблице 2.2.
| Свойство | Значение |
|---|---|
| Alignment | Выравнивание содержимого свойства Text на панели |
| AutoSize | Изменение размеров панели по содержимому |
| BorderStyle | Внешний вид панели – утопленная, приподнятая или без выделения |
| Icon | Добавление иконки |
| Style | Стиль панели |
| Text | Текст, располагаемый на панели |
| ToolTipText | Всплывающая подсказка — появляется при наведении курсора на панель |
| Width | Ширина панели в пикселях |
| Name | Название панели для обращения к ней в коде |
Свойства панели, назначаемые в окне редактора StatusBarCollectionEditor, можно изменять в коде —именно так мы сейчас и поступим.
После завершения работы над панелями закрываем редактор. Свойству ShowPanels элемента управления StatusBar устанавливаем значение True. На форме немедленно отображаются две панели.
Выделяем элемент управления RichTextBox, в окне его свойств переключаемся на события и создаем обработчик для события TextChanged:
private void richTextBox1_TextChanged(object sender, System.EventArgs e)
{
//Свойству Text панели sbAmount устанавливаем надпись "Аmount of symbols"
//и длину текста в RichTextBox.
sbAmount.Text = "Аmount of symbols" + richTextBox1.Text.Length.ToString();
}
Свойство Text панели sbAmount мы изменяем программно: даже если бы мы ничего не написали в окне редактора StatusBarCollectionEditor, при возникновении события TextChanged на панели появится надпись.
Займемся теперь второй панелью — той, на которую будем выводить системное время. В конструкторе формы blank добавляем код:
public blank()
{
InitializeComponent();
//Свойству Text панели sbTime устанавливаем системное время,
// конвертировав его в тип String
sbTime.Text = Convert.ToString(System.DateTime.Now.ToLongTimeString());
//В тексте всплывающей подсказки выводим текущую дату
sbTime.ToolTipText = Convert.ToString(System.DateTime.Today.ToLongDateString());
}
Запускаем приложение. Панель с выводимым временем располагается достаточно необычно (рис. 2.22), при необходимости для вывода времени в привычном правом нижнем углу можно добавить третью пустую панель.
(рис 2.22) Строка состояния с двумя панелями
При запуске приложения Notepad С# на форме имеются три стандартные кнопки — "Свернуть", "Развернуть" и "Закрыть". Большинство пользователей предпочитают использовать именно кнопку "Закрыть" для выхода из приложения. Тем не менее принято дублировать кнопку формы пунктом меню Exit. В обработчике этой кнопки добавляем код
private void mnuExit_Click(object sender, System.EventArgs e)
{
this.Close();
}
Метод Close закрывает форму и может быть назначен другим элементам управления — например, кнопке.
Чекбоксы относятся к так называемым кнопкам
| FindForm, форма, свойство | Значение |
|---|---|
| Name | FindForm |
| FormBorderStyle | FixedToolWindow |
| Size | 328; 112 |
| Text | Find |
Располагаем на форме TextBox, две кнопки и два элемента CheckBox так, как показано на рис. рис. 2.23:
(рис 2.23) Форма FindForm в режиме дизайнаУстанавливаем следующие свойства элементам управления:
| TextBox, свойство | Значение |
|---|---|
| Name | txtFind |
| Size | 192; 20 |
| Text |
| checkBox1, свойство | Значение |
|---|---|
| Name | cbMatchCase |
| Text | Match Case |
| checkBox2, свойство | Значение |
|---|---|
| Name | cbMatchWhole |
| Text | Match whole word |
| button1, свойство | Значение |
|---|---|
| Name | btnOK |
| DialogResult | OK |
| Text | OK |
| button2, свойство | Значение |
|---|---|
| Name | btnCancel |
| DialogResult | Cancel |
| Text | Cancel |
Выбор первого чекбокса — cbMatchCase — будет устанавливать поиск слова с учетом регистра, второго – cbMatchWhole — поиск по целому слову. Обратите внимание на свойство кнопок DialogResult — выбирая соответствующие свойства, мы устанавливаем обработчики для кнопок без обращения к коду. Значение ОК закрывает форму, выполняя установленное действие, — в данном случае — поиск; значение Cancel просто закрывает форму. В главном меню формы frmmain добавляем разделительную линию и пункт Find и устанавливаем значения свойств: Name — mnuFind, Shortcut — CtrlF, Text — Find.
Переходим в обработчик этого пункта:
private void mnuFind_Click(object sender, System.EventArgs e)
{
//Создаем новый экземпляр формы FindForm
FindForm frm = new FindForm();
//Если выбран результат DialogResult.Cancel, закрываем форму (до этого
//мы использовали DialogResult.OK)
if(frm.ShowDialog(this) == DialogResult.Cancel) return;
////Переключаем фокус на данную форму.
blank form = (blank)this.ActiveMdiChild;
////Указываем, что родительской формой является форма frmmain
form.MdiParent = this;
//Вводим переменную для поиска в определенной части текста —
//поиск слова будет осуществляться от текущей позиции курсора
int start = form.richTextBox1.SelectionStart;
//Вызываем предопределенный метод Find элемента richTextBox1.
form.richTextBox1.Find(frm.FindText, start, frm.FindCondition);
}
Основой поиска будет метод Find элемента управления RichTextBox. Нам остается лишь указать параметры поиска, которые могут принимать различные значения (рис. 2.24):
(рис 2.24) Параметры метода Find. Щелкая на маленькую кнопку всплывающей подсказки Intel Sense, выбираем разные подсказки для групп передаваемых параметровВ коде формы FindForm осталось реализовать логику работы, зависящую от положения элементов CheckBox:
// Создаем перечисление, возвращающее параметр FindCondition
public RichTextBoxFinds FindCondition
{
get
{
//Выбраны два чекбокса
if (cbMatchCase.Checked cbMatchWhole.Checked)
{
// Возвращаем свойство MatchCase и WholeWord
return RichTextBoxFinds.MatchCase| RichTextBoxFinds.WholeWord;
}
//Выбран один чекбокс
if (cbMatchCase.Checked )
{
// Возвращаем свойство MatchCase
return RichTextBoxFinds.MatchCase;
}
//Выбран другой чекбокс
if (cbMatchWhole.Checked )
{
// Возвращаем свойство WholeWord
return RichTextBoxFinds.WholeWord;
}
//Не выбран ни один чекбокс
return RichTextBoxFinds.None;
}
}
И наконец, создаем свойство FindText, возвращающее в качестве переменной поиска введенный текст в текстовое поле формы FindForm:
public string FindText
{
get{return txtFind.Text;}
set{txtFind.Text = value;}
}
Запускаем приложение. Выбирая различные варианты, можно однократно искать заданное слово (рис. 2.25):
(рис 2.25) Поиск слова в тексте
Многие пользователи предпочитают работать по большей части с клавиатурой и прибегать к помощи мыши только там, где без нее нельзя обойтись. При работе с формой Find было бы удобно ввести слово в текстовое поле, затем, нажав клавишу Tab и Enter, осуществить поиск, — или, дважды нажав клавишу Tab, переключить фокус ввода на чекбокс Match Case. Для этого в режиме дизайна формы Find следует установить свойство TabIndex элементов управления в виде последовательной нумерации, начиная с нуля:
| Элемент управления | TabIndex |
|---|---|
| TxtFind | 0 |
| BtnOK | 1 |
| CbMatchCase | 2 |
| CbMatchWhole | 3 |
| BtnCancel | 4 |
При такой нумерации фокус ввода будет последовательно переходить в порядке возрастания — от элемента txtFind до btnCancel. Свойство TabIndex имеет особенно большое значение при создании ряда текстовых полей, где пользователю будет предлагаться ввести информацию.
Программы, как правило, содержат пункт главного меню "О программе", где в отдельном окне помещается логотип компании, лицензионное соглашение, гиперссылки на сайт разработчика и другая информация. Создадим подобную форму, используя новые элементы управления — Label, LinkLabel и PictureBox.
Итак, добавим в наш проект новую форму и назовем ее About.cs. Установим следующие свойства формы:
| About, форма, свойство | Значение |
|---|---|
| Name | About |
| FormBorderStyle | FixedSingle |
| MaximizeBox | False |
| MinimizeBox | False |
| Size | 318; 214 |
| Text | About Notepad C# |
Добавим на форму элемент управления PictureBox — он представляет собой подложку, размещаемую на форме, которая может содержать в себе рисунки для отображения. В поле свойства Image щелкаем на кнопку (…) и выбираем рисунок по адресу Code\Glava2\NotepadCSharp\Icon\logo.gif. Поскольку logo.gif является анимированным рисунком, элемент PictureBox начинает воспроизводить анимацию сразу же, даже в режиме дизайна.
Из окна ToolBox перетащим на форму кнопку, Label и LinkLabel. В поле свойства Text кнопки введем OK. Элемент Label предназначен для размещения на форме надписей, которые в готовом приложении будут доступны только для чтения. В поле свойства Text введем Notepad C# 2006 All rights reserved. Элемент LinkLabel отображает текст на форме в стиле web-ссылок и обычно используется для создания навигации между формами или ссылки на сайт. В поле Text этого элемента вводим адрес гипотетического сайта — www.notepadcsharp.com. Пользователь будет переходить на сайт, нажимая на эту ссылку, поэтому реализуем переход по гиперссылке для события Click. В окне Properties щелкаем дважды на событии Click и добавляем обработчик:
private void linkLabel1_Click(object sender, System.EventArgs e)
{
//Добавляем блок для обработки исключений — по разным причинам
//пользователь может не получить доступа к ресурсу.
try
{
//Вызываем метод VisitLink, определенный ниже
VisitLink();
}
catch (Exception ex )
{
MessageBox.Show(ex +"Unable to open link that was clicked.");
}
}
//Создаем метод VisitLink
private void VisitLink()
{
// Изменяем цвет посещенной ссылки, программно
//обращаясь к свойству LinkVisited элемента LinkLabel
linkLabel1.LinkVisited = true;
//Вызываем метод Process.Start method для запуска браузера,
//установленного по умолчанию, и открытия ссылки
System.Diagnostics.Process.Start("http://www.notepadcsharp.com");
}
Кнопка OK просто будет закрывать форму:
private void button1_Click(object sender, System.EventArgs e)
{
this.Close();
}
В пункте главного меню About Programm… формы frmmain добавляем процедуру вызова формы About:
private void mnuAbout_Click(object sender, System.EventArgs e)
{
//Создаем новый экземпляр формы About
About frm = new About();
frm.Show();
}
Запускаем приложение (рис. 2.26):
(рис 2.26) Окно About Notepad C#
В приложении Notepad C# с открытой формой About без труда можно вернуться к другим пунктам меню программы или документу, т. е. форма About позволяет переключать фокус. Такое поведение дочерних форм характерно для панелей инструментов в программах и называется немодальным. Наоборот, форма, запущенная в модальном режиме, не позволит работать с приложением до тех пор, пока мы не закроем эту форму. Для открытия формы в модальном режиме используется метод ShowDialog:
private void mnuAbout_Click(object sender, System.EventArgs e)
{
//Создаем новый экземпляр формы About
About frm = new About();
frm.ShowDialog();
}
С модификаторами доступа вы сталкивались, когда изучали синтаксис языка C#. Используя их, можно определить область видимости, иначе говоря, уровень доступности типов и членов классов, — под этим понимается участок кода, из любой точки которого будет доступен запрашиваемый тип или член класса. Технология
| Модификатор | Определение |
|---|---|
| public (общественный, открытый) | Объект доступен любому коду из любой сборки |
| private (частный, закрытый) | Объект может быть вызван другими методами только из того же типа |
| internal (внутренний, сборочный) | Объект может быть вызван любым кодом из той же сборки |
| protected (защищенный, родовой) | Объект может быть вызван производными типами независимо от их сборки |
| protected internal (родовой сборочный) | Объект может быть вызван производными типами, определенными в той же самой сборке |
В качестве объекта могут выступать методы, свойства, классы и, как мы далее увидим, — формы. Под сборкой здесь понимается функциональная единица кода (строгое определение сборок см. в лекции 9).
Наследование классов — достаточно простое и чрезвычайно удобное понятие синтаксиса С#. Формы, которые содержат большую часть методов и свойств, определенных как public, тоже можно наследовать — для получения доступа к свойствам, определенным как protected, и для ускорения работы. В самом деле, если у нас имеется уже готовая форма (например, About Notepad C#), которую мы собираемся использовать в нескольких приложениях, удобно просто создать наследуемую форму.
Запускаем приложение Notepad C# и в окне Solution Explorer щелкаем правой кнопкой на названии проекта. В появившемся контекстном меню выбираем Add\Add Inherited Form… . В окне Add New Item задаем название формы — IAbout.cs. Далее появляется окно Inheritance Picker, в котором отображаются все формы текущего проекта (рис. 2.27).
(рис 2.27) Окно выбора формы для наследования Inheritance PickerВ этом окне мы выбираем форму About. Обратите внимание на кнопку Browse, позволяющую искать формы для наследования в библиотеках dll. Нажимаем кнопку OK — в проекте появилась новая форма, содержащая все элементы управления формы About (рис. 2.28). Для завершения связей необходимо скомпилировать проект cнова — выбрав пункт главного меню Build/
(рис 2.28) Форма IAbout, наследованная от формы AboutПри редактировании родительской формы изменения также касаются дочерней — добавьте, например, кнопку на форму About, и она появится на форме IAbout. Изменения же, производимые с дочерней формой, не затрагивают родительскую форму.
Панели инструментов ToolBar содержат наборы кнопок, как правило, дублирующих пункты главного меню. В графических программах панели инструментов — основное средство работы. Откроем снова приложение Notepad C# и перетащим из окна ToolBox элемент управления ToolBar. На кнопках панели обычно располагаются иконки, поэтому, прежде чем мы начнем заниматься ими, нам следует подумать о рисунках. Добавим на форму элемент управления ImageList, применяемый для хранения рисунков, которые могут быть использованы для оформления приложения. Щелкнем в поле Images элемента ImageList (рис. 2.29).
(рис 2.29) Cвойство Images элемента ImageListДобавим файлы иконок, последовательно нажимая кнопку Add и выбирая директорию — Code\Glava2\NotepadCSharp\Icon. Мы создадим кнопки панели инструментов, дублирующие действия пунктов меню New, Open, Save, Cut, Copy и Paste, поэтому вы можете выбрать подходящие изображения на своем ImageCollectionEditor, нажимая OK. Займемся теперь элементом ToolBar. Свойству Name установим значение toolBarMain, а в поле свойства ImageList выберем imageList1. Запустим редактор ToolBarButton Collection Editor для
(рис 2.30) Редактор ToolBarButton Collection EditorДля добавления кнопок в этом редакторе тоже следует нажимать клавишу Add. Создадим шесть кнопок, установив для них следующие свойства:
| Name | Image Index | ToolTipText |
|---|---|---|
| tbNew | ![]() |
Create New |
| tbOpen | ![]() |
Open |
| tbSave | ![]() |
Save |
| tbCut | ![]() |
Cut |
| tbCopy | ![]() |
Copy |
| tbPaste | ![]() |
Paste |
Свойство Name устанавливает название кнопки для обращения к ней в коде. Свойство Image Index определяет изображение на кнопке, а в поле ToolTipText вводим текст всплывающей подсказки, которая будет появляться при наведении курсора на кнопку. Завершив работу с редактором кнопок в режиме дизайна формы frmmain, дважды щелкаем на ToolBar и переходим в код. Для создания функциональности кнопок связываем событие Click заданной кнопки c соответствующим обработчиком пунктов меню:
private void toolBarMain_ButtonClick(object sender, System.Windows.Forms.ToolBarButtonClickEventArgs e)
{
//New
if (e.Button.Equals(tbNew))
{
mnuNew_Click(this, new EventArgs());
}
//Open
if (e.Button.Equals(tbOpen))
{
mnuOpen_Click(this, new EventArgs());
}
//Save
if (e.Button.Equals(tbSave))
{
mnuSave_Click(this, new EventArgs());
}
//Cut
if (e.Button.Equals(tbCut))
{
mnuCut_Click(this, new EventArgs());
}
//Copy
if (e.Button.Equals(tbCopy))
{
mnuCopy_Click(this, new EventArgs());
}
//Paste
if (e.Button.Equals(tbPaste))
{
mnuPaste_Click(this, new EventArgs());
}
}
Запускаем приложение. Кнопки панели инструментов дублируют пункты меню, а при наведении на них появляются подсказки (рис. 2.31).
(рис 2.31) Панель инструментов ToolbarНа диске, прилагаемом к книге, вы найдете приложение NotepadCSharp (Code\Glava2\NotepadCSharp). В конце этой лекции приводится листинг форм frmamin и blank.
При изучении синтаксиса языка С# вы сталкивались с чтением и записью файлов. Если при рассмотрении обработчиков OpenFileDialog и SaveFileDialog вы не до конца поняли, как .NET Framework работает с файлами, давайте еще раз разберемся с этим понятием.
Файл — это совокупность данных, сохраненных на диске под общим названием. Когда мы открываем файл, он становится потоком, с которым мы можем осуществлять следующие операции:
В С# все классы, которые представляют потоки, наследуются от абстрактного класса Stream. Класс Stream вместе со своими подклассами обеспечивает универсальное представление источников данных и архивов, абстрагированное от подробностей операционной системы. Классы потоков определены в пространстве имен System.IO.
Для чтения и записи файлов, содержащих только текст, используются классы StreamReader и StreamWriter. Класс Stream Reader наследуется от класса TextReader, который считывает строки из стандартного текстового файла. Класс StreamWriter наследуется от класса TextWriter, записывающего символы в поток в специальном кодировании.
Создайте новое консольное приложение и назовите его FileStream. Скомпилируйте приложение (Ctrl+F5). В папке проекта создайте текстовый документ 1.txt. Откройте его в блокноте (или в приложении Notepad C#) и напишите в нем любой текст на русском и английском языках, сохранив затем его в кодировке Unicode. Выведем теперь записанный текст в окно консольного приложения. Переходим в код FileStream и подключаем пространство имен:
using System.IO;
В методе Main добавляем код:
[STAThread]
static void Main(string[] args)
{
//Cоздаем экземпляр Chitat класса StreamReader и указываем путь к файлу
и его название
StreamReader Chitat = new StreamReader("1.txt");
// Объявляем переменную A.
string A;
//В переменную А считываем содержимое файла
A = Chitat.ReadToEnd();
//Закрываем поток
Chitat.Close();
//Выводим переменную A в окно консольного приложения.
Console.WriteLine(A);
}
Когда вы работаете с файлом, например, редактируете документ Microsoft Word, вы не сможете удалить его или переместить — потому что приложение занято и поток открыт. Только завершив работу с документом и, следовательно, закрыв поток, можно перемещать его или открывать с помощью других приложений. Аналогично, в этом примере мы закрываем поток, вызывая метод Close, освобождая тем самым задействованные системные ресурсы.
Запускаем приложение. В консольном окне появляется текст, считанный из файла (рис. 2.32 ).
(рис 2.32) Чтение текста из файлаДобавим теперь объект класса StreamWriter, который будет записывать текст в файл:
[STAThread]
static void Main(string[] args)
{
//Cоздаем экземпляр Chitat класса StreamReader и указываем путь к файлу и его название
StreamReader Chitat = new StreamReader("1.txt");
// Объявляем переменную A.
string A;
//В переменную А считываем содержимое файла
A = Chitat.ReadToEnd();
//Закрываем поток
Chitat.Close();
//Выводим переменную A в окно консольного приложения.
Console.WriteLine(A);
//Cоздаем экземпляр Pisat класса StreamWriter
StreamWriter Pisat = new StreamWriter("1.txt", true, System.Text.Encoding.Unicode);
//Вызываем метод Write экземпляра Pisat
Pisat.Write("Добавляем текст");
//Закрываем поток
Pisat.Close();
// Для того, чтобы не переходить в директорию
//для просмотра файла вручную, выведем его еще раз
StreamReader ChitatSnova = new StreamReader("1.txt");
string B;
B = ChitatSnova.ReadToEnd();
ChitatSnova.Close();
Console.WriteLine(B);
}
Метод Write добавил строку в файл (рис. 2.33):
(рис 2.33) Чтение и запись текста из файлаНа диске, прилагаемом к книге, вы найдете приложение FileStream (Code\Glava2\ FileStream).
В первой лекции мы рассматривали окно Object Browser. Использование этого окна зачастую может быть гораздо более удобным, чем поиск справочной информации в MSDN.
В предыдущем примере, при создании экземпляра Pisat класса StreamWriter следует указывать параметры, передаваемые классу, — при использовании Intel Sense всплывающая подсказка указывает, какие именно параметры следует передавать (рис. 2.34).
(рис 2.34) Группа из семи различных вариантов, предлагаемых Intel Sense. Для перемещения между вариантами щелкаем на кнопку со стрелкой — вариант 1 of 7Следуя подсказке, мы могли указать и передать такие параметры:
StreamWriter Pisat = new StreamWriter("1.txt");
В этом случае файл 1.txt перезаписывался и текстовая строка помещалась в пустой файл. Для добавления в файл нужно указывать булевскую переменную:
StreamWriter Pisat = new StreamWriter("1.txt", true);
В этом случае можно было бы добавлять в файл текст, содержащий только латинские буквы. Для корректной записи кириллицы следует указывать кодировку, например Unicode, что мы и сделали:
StreamWriter Pisat = new StreamWriter("1.txt", true, System.Text.Encoding.Unicode);
Возможны и другие варианты передаваемых параметров — например, указание размера передаваемого буфера в байтах.
Предположим, мы не знаем, какую именно кодировку следует указывать. В самом деле, Intel Sense на рис. 2 не указывает, что именно кодировка Unicode принадлежит пространству имен System.Text.Encoding. Но мы можем просмотреть все доступные объекты и свойства этого пространства, используя окно Object Browser (рис. 2.35).
(рис 2.35) Пространство имен System.Text.Encoding в окне Object BrowserВ части окна Members отображаются и другие доступные кодировки, например, ASCII.
При редактировании файла требуется определять его наличие на жестком диске для выбора потом варианта сохранения — целиком или только внесенных изменений. Создайте новое консольное приложение и назовите его FileExists. Следующий код демонстрирует проверку файла на диске:
using System.IO;
…
[STAThread]
static void Main(string[] args)
{
//Выводим сообщение
Console.WriteLine("Ведите название файла");
// Создаем переменную nazvaniefayla, в которую
//запишем название файла, введеное пользователем.
string nazvaniefayla = Console.ReadLine();
//Проверяем наличие файла (в директории bin/Debug)
if (File.Exists(nazvaniefayla))
{
//Если файл существует, выводим его в консольное окно.
StreamReader chitat = new StreamReader(nazvaniefayla);
string A;
A = chitat.ReadToEnd();
chitat.Close();
Console.WriteLine(A);
}
else
{
//Если файл не найден, выводим окно сообщения
Сonsole.WriteLine("Файл с указанным именем не существует. Сoздать его Y/N");
//Считываем результат пользователя
string rezultatvibora = Console.ReadLine();
if ((rezultatvibora=="Y")||(rezultatvibora=="y"))
{
//Создаем новый файл.
StreamWriter pisat = new StreamWriter(nazvaniefayla);
Console.WriteLine("Введите текст");
string vvedemtext = Console.ReadLine();
pisat.WriteLine(vvedemtext);
pisat.Close();
Console.WriteLine("Файл создан");
}
else
{
// Если пользователь отказался от создания файла, выводим сообщение.
Console.WriteLine("Ничего не будет созданно");
}
}
}
На диске, прилагаемом к книге, вы найдете приложение FileExists (Code\Glava2\FileExists).
В рассмотренном выше примере мы проверяли наличие файла в папке Bin/Debug, где находится само приложение. В практических случаях подобная директория не может нас устраивать — требуется просматривать заданные каталоги и папки. В C# можно работать с файлами и каталогами, используя классы DirectoryInfo и FileInfo, предоставляющие всю информацию о файлах и папках.
Класс DirectoryInfo обычно применяется для таких операций, как копирование, перемещение, переименование, создание и удаление папок. Этот класс содержит метод GetFiles(), который возвращает список файлов из текущего каталога.
Класс FileInfo предоставляет методы для создания, копирования, удаления, перемещения и открытия файлов, а также является вспомогательным классом при создании объекта FileStream.
Cоздайте новое консольное приложение и назовите его DirectoryInfo. Следующий простой код выводит список всех файлов, содержащихся на диске С:
using System;
using System.IO;
namespace DirectoryInformation
{
class Class1
{
[STAThread]
static void Main(string[] args)
{
//Создаем экземпляр di класса DirectoryInfo и указываем диск С в качестве директории
DirectoryInfo directoriya = new DirectoryInfo("C:\\");
// Получаем список всех папок, содержащихся на диске С:\
DirectoryInfo[] poddirectoriya = directoriya.GetDirectories();
foreach (DirectoryInfo dd in poddirectoriya)
{
//Проверяем наличие доступа к каталогу
if(dd.Attributes == FileAttributes.Directory)
{
// Получаем список всех файлов из каталога
FileInfo[] spisokfile= dd.GetFiles();
foreach (FileInfo fi in spisokfile)
{
//Выводим список файлов
Console.WriteLine(fi.ToString());
}
}
}
}
}
}
На диске, прилагаемом к книге, вы найдете приложение DirectoryInfo — Code\Glava2\DirectoryInfo.
Для более общего способа чтения и записи файлов используются классы BinaryReader и BinaryWriter, предназначенные для чтения двоичных данных. Любой файл в конечном итоге представляет собой набор двоичных данных, следовательно, эти данные можно считывать и записывать во внутреннем, двоичном формате. Класс BinaryWriter представляет собой оболочку для байтового потока, управляющей записью двоичных данных. Класс BinaryReader является оболочкой, содержащей байтовый поток, и выполняет чтение двоичных данных.
Рассмотрим приложение, позволяющее считывать файл формата MP3 и записывать фрагмент этого файла. Создайте новое консольное приложение и назовите его BinaryReadWrite. В папку bin/Debug поместите любой музыкальный файл формата MP3, имеющийся на вашем компьютере.
Подключаем пространство имен:
using System.IO;
Добавляем код:
[STAThread]
static void Main(string[] args)
{
//Добавляем блок обработки исключений
try
{
//Создаем новый поток Chtenie и указываем файл для чтения — music.mp3
FileStream Chtenie = new FileStream("music.mp3", FileMode.Open);
//Создаем экземпляр br класса BinaryReader и
//связываем его с потоком Chtenie
BinaryReader br = new BinaryReader(Chtenie);
// Создаем массив типа байтов и
//передаем ему размер в байтах – (например, 1000000) записываемого файла
byte[] n = br.ReadBytes(1000000);
//Закрываем поток
br.Close();
//Создаем новый поток Zapis и указываем название
//файла для записи sozdanajamuzika.mp3
FileStream Zapis = new FileStream("newmusic.mp3", FileMode.CreateNew, FileAccess.Write);
//Создаем экземпляр wr класса BinaryWriter и
//связываем его с потоком Zapis
BinaryWriter wr = new BinaryWriter(Zapis);
// Можно связывать объект wr с потоком создавая его без названия:
//BinaryWriter wr = new BinaryWriter(new FileStream("sozdanajamuzika.mp3", //FileMode.CreateNew, FileAccess.Write));
//Передаем в поток массив байтов n
wr.Write(n);
//Закрываем поток
br.Close();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
Запускаем приложение. Если все сработает без ошибок — на экране появится станадртное сообщение Press any key to continue, в противном случае — поскольку мы включили блок исключений — выйдет диагностическое сообщение. Перейдем в папку bin/Debug. В ней появился файл newmusic.mp3, прослушать который мы можем с помощью любого музыкального проигрывателя.
Рассмотрим перечисления в конструкторах FileStream. Параметр FileMode определяет, каким образом открывается файл (рис. 2.36):
(рис 2.36) Перечисления FileModeЗначения перечисления FileMode указаны в таблице 2.4.
| Значение | Описание |
|---|---|
| Append | Если файл существует, он открывается, если нет — создается новый. Данные добавляются в конец файла |
| Create | Создается новый выходной файл; если файл с таким названием существует, он перезаписывается |
| Создается новый выходной файл; если файл с таким названием уже существует, генерируется исключение IOException | |
| Open | Открывается существующий файл; если файла с таким названием не существует, генерируется исключение FileNotFoundException |
| OpenOrCreate | Открывается существующий файл; если файл не существует, он создается |
| Truncate | Открывается существующий файл, но его длина усекается до нуля |
Параметр FileAccess определяет для пользователя разрешение на доступ к файлу (рис. 2.37):
(рис 2.37) Перечисления FileAccessЗначения перечисления FileAccess указаны в таблице 2.5.
| Значение | Описание |
|---|---|
| Read | Доступ на чтение из файла |
| ReadWrite | Разрешается чтение из файла и |
| Write | Доступ для записи в файл |
Дополнительно для управления режимом доступа при одновременной работе с файлами нескольких потоков используется перечисление FileShare (рис. 2.38). Например, при создании потока для чтения файла мы могли полностью определить все параметры следующим образом:
FileStream Chtenie = new FileStream("music.mp3", FileMode.Open,
FileAccess.Read, FileShare.Read);
(рис 2.38) Перечисления FileShareЗначения перечисления FileShare указаны в таблице 2.6.
| Значение | Описание |
|---|---|
| Inheritable | Дает доступ к файлам, образованных текущим потоком |
| None | Запрещает совместное использование текущего файла. Пока файл открыт, доступ к нему будет блокирован |
| Read | Позволяет открывать текущей файл для чтения |
| ReadWrite | Позволяет открывать текущий файл для чтения или записи |
| Write | Позволяет открывать текущий файл для записи |
На диске, прилагаемом к книге, вы найдете приложение BinaryReadWrite (Code\Glava2\ BinaryReadWrite).
Иногда в приложениях требуется запускать программы, входящие в состав операционной системы или установленные на данном компьютере. Создайте новое Windows-приложение и назовите его RunProgramm. На появившейся форме расположите три кнопки:
| button1, Свойства | Значения свойств |
|---|---|
| Name | btnSystemInfo |
| Size | 168;23 |
| Text | Информация о системе |
| button2, Свойства | Значения свойств |
|---|---|
| Name | btnRegEdit |
| Size | 168;23 |
| Text | Редактор реестра |
| button3, Свойства | Значения свойств |
|---|---|
| Name | btnExplorer |
| Size | 168;23 |
| Text | Проводник |
Располагаем кнопки в центре формы и выравниваем их, используя пункт меню Format. В коде формы подключаем пространство имен Diagnostics, позволяющее запускать приложения:
using System.Diagnostics;
Добавляем обработчики кнопок:
private void btnSystemInfo_Click(object sender, System.EventArgs e)
{
//Добавляем блок обработки исключений — по разным причинам (например,
//система установлена на другом диске) приложение может быть недоступным.
try
{
//Создаем новый экземпляр SysInfo класса Process
Process SysInfo = new Process();
// Если приложение не будет работать корректно — вызываем диалоговое окно ошибок.
SysInfo.StartInfo.ErrorDialog = true;
//Указываем путь к запускаемому приложению "Сведения о системе"
SysInfo.StartInfo.FileName = "C:\\Program Files\\Common Files\\Microsoft Shared\\MSInfo\\msinfo32.exe";
//Запускаем SysInfo
SysInfo.Start();
}
catch (Exception ex)
{
MessageBox.Show (ex.Message);
}
}
private void btnRegEdit_Click(object sender, System.EventArgs e)
{
try
{
Process RegEdit = new Process();
RegEdit.StartInfo.ErrorDialog = true;
//Указываем путь к запускаемому приложению "Редактор реестра"
RegEdit.StartInfo.FileName = "C:\\Windows\\regedit.exe";
RegEdit.Start();
}
catch (Exception ex)
{
MessageBox.Show (ex.Message);
}
}
private void btnExplorer_Click(object sender, System.EventArgs e)
{
try
{
Process Explorer = new Process();
Explorer.StartInfo.ErrorDialog = true;
//Указываем путь к запускаемому приложению "Проводник"
Explorer.StartInfo.FileName = "C:\\Windows\\explorer.exe";
Explorer.Start();
}
catch (Exception ex)
{
MessageBox.Show (ex.Message);
}
}
Запускаем приложение. При нажатии на кнопки запускаются соответствующие приложения (рис. 2.39).
(рис 2.39) Запуск программ из приложения RunProgrammДля запуска других программ или отдельных исполняемых файлов вашего приложения следует указывать их название и адрес, по которому они будут отыскиваться на клиентском компьютере.
На диске, прилагаемом к книге, вы найдете приложение RunProgramm (Code\Glava2\RunProgramm).
using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.IO;
namespace NotepadCSharp
{
public class frmmain : System.Windows.Forms.Form
{
private System.Windows.Forms.MainMenu mainMenu1;
private System.Windows.Forms.MenuItem menuItem5;
private System.Windows.Forms.MenuItem menuItem12;
private System.Windows.Forms.MenuItem mnuFile;
private System.Windows.Forms.MenuItem mnuNew;
private System.Windows.Forms.MenuItem mnuOpen;
private System.Windows.Forms.MenuItem mnuSave;
private System.Windows.Forms.MenuItem mnuExit;
private System.Windows.Forms.MenuItem mnuEdit;
private System.Windows.Forms.OpenFileDialog openFileDialog1;
private System.Windows.Forms.MenuItem mnuCut;
private System.Windows.Forms.MenuItem mnuCopy;
private System.Windows.Forms.MenuItem mnuPaste;
private System.Windows.Forms.MenuItem mnuDelete;
private System.Windows.Forms.MenuItem mnuSelectAll;
private System.Windows.Forms.MenuItem mnuHelp;
private System.Windows.Forms.MenuItem mnuAbout;
private System.Windows.Forms.MenuItem mnuArrangeIcons;
private System.Windows.Forms.MenuItem mnuCascade;
private System.Windows.Forms.MenuItem mnuTileHorizontal;
private System.Windows.Forms.MenuItem mnuTileVertical;
private System.Windows.Forms.MenuItem mnuWindow;
private int openDocuments = 0;
private System.Windows.Forms.MenuItem mnuFormat;
private System.Windows.Forms.SaveFileDialog saveFileDialog1;
private System.Windows.Forms.MenuItem mnuSaveAs;
private System.Windows.Forms.FontDialog fontDialog1;
private System.Windows.Forms.MenuItem mnuFont;
private System.Windows.Forms.MenuItem mnuColor;
private System.Windows.Forms.ColorDialog colorDialog1;
private System.Windows.Forms.MenuItem menuItem1;
private System.Windows.Forms.MenuItem mnuFind;
private System.Windows.Forms.ToolBarButton tbNew;
private System.Windows.Forms.ToolBarButton tbOpen;
private System.Windows.Forms.ToolBarButton tbSave;
private System.Windows.Forms.ToolBarButton tbCut;
private System.Windows.Forms.ToolBarButton tbCopy;
private System.Windows.Forms.ToolBarButton tbPaste;
private System.Windows.Forms.ImageList imageList1;
private System.Windows.Forms.ToolBar toolBarMain;
private System.ComponentModel.IContainer components;
public frmmain()
{
//
// Required for Windows Form Designer support
//
InitializeComponent();
mnuSave.Enabled = false;
//
// 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
[STAThread]
static void Main()
{
Application.Run(new frmmain());
}
private void mnuNew_Click(object sender, System.EventArgs e)
{
//Создаем новый экземпляр формы frm
blank frm = new blank();
frm.DocName = "Untitled " + ++openDocuments;
//Указываем, что родительским контейнером
//нового экземпляра будет эта, главная форма.
frm.MdiParent = this;
frm.Text = frm.DocName;
//Вызываем форму
frm.Show();
}
private void mnuArrangeIcons_Click(object sender, System.EventArgs e)
{
this.LayoutMdi(MdiLayout.ArrangeIcons);
}
private void mnuCascade_Click(object sender, System.EventArgs e)
{
this.LayoutMdi(MdiLayout.Cascade);
}
private void mnuTileHorizontal_Click(object sender, System.EventArgs e)
{
this.LayoutMdi(MdiLayout.TileHorizontal);
}
private void mnuTileVertical_Click(object sender, System.EventArgs e)
{
this.LayoutMdi(MdiLayout.TileVertical);
}
private void mnuCut_Click(object sender, System.EventArgs e)
{
blank frm = (blank)this.ActiveMdiChild;
frm.Cut();
}
private void mnuCopy_Click(object sender, System.EventArgs e)
{
blank frm = (blank)this.ActiveMdiChild;
frm.Copy();
}
private void mnuPaste_Click(object sender, System.EventArgs e)
{
blank frm = (blank)this.ActiveMdiChild;
frm.Paste();
}
private void mnuDelete_Click(object sender, System.EventArgs e)
{
blank frm = (blank)this.ActiveMdiChild;
frm.Delete();
}
private void mnuSelectAll_Click(object sender, System.EventArgs e)
{
blank frm = (blank)this.ActiveMdiChild;
frm.SelectAll();
}
private void mnuOpen_Click(object sender, System.EventArgs e)
{
//Можно программно задавать доступные для обзора расширения файлов.
//openFileDialog1.Filter = "Text Files (*.txt)|*.txt|All Files(*.*)|*.*";
//Если выбран диалог открытия файла, выполняем условие
if (openFileDialog1.ShowDialog() == DialogResult.OK)
{
//Создаем новый документ
blank frm = new blank();
//Вызываем метод Open формы blank
frm.Open(openFileDialog1.FileName);
//Указываем, что родительской формой является форма frmmain
frm.MdiParent = this;
//Присваиваем переменной DocName имя открываемого файла
frm.DocName = openFileDialog1.FileName;
//Свойству Text формы присваиваем переменную DocName
frm.Text = frm.DocName;
//Вызываем форму frm
frm.Show();
mnuSave.Enabled = true;
}
}
private void mnuSave_Click(object sender, System.EventArgs e)
{
//Переключаем фокус на данную форму.
blank frm = (blank)this.ActiveMdiChild;
//Вызываем метод Save формы blank
frm.Save(frm.DocName);
frm.IsSaved = true;
}
private void mnuSaveAs_Click(object sender, System.EventArgs e)
{
mnuSave.Enabled = true;
//Можно программно задавать доступные для обзора расширения файлов
//openFileDialog1.Filter = "Text Files (*.txt)|*.txt|All Files(*.*)|*.*";
//Если выбран диалог открытия файла, выполняем условие
if (saveFileDialog1.ShowDialog() == DialogResult.OK)
{
//Переключаем фокус на данную форму.
blank frm = (blank)this.ActiveMdiChild;
//Вызываем метод Save формы blank
frm.Save(saveFileDialog1.FileName);
//Указываем, что родительской формой является форма frmmain
frm.MdiParent = this;
//Присваиваем переменной FileName имя сохраняемого файла
frm.DocName = saveFileDialog1.FileName;
//Свойству Text формы присваиваем переменную DocName
frm.Text = frm.DocName;
frm.IsSaved = true;
}
}
private void mnuExit_Click(object sender, System.EventArgs e)
{
this.Close();
}
private void mnuFont_Click(object sender, System.EventArgs e)
{
//Переключаем фокус на данную форму.
blank frm = (blank)this.ActiveMdiChild;
//Указываем, что родительской формой является форма frmmain
frm.MdiParent = this;
//Вызываем диалог
fontDialog1.ShowColor = true;
//Связываем свойства SelectionFont и SelectionColor элемента RichTextBox
//с соответствующими свойствами диалога
fontDialog1.Font = frm.richTextBox1.SelectionFont;
fontDialog1.Color = frm.richTextBox1.SelectionColor;
//Если выбран диалог открытия файла, выполняем условие
if (fontDialog1.ShowDialog() == DialogResult.OK)
{
frm.richTextBox1.SelectionFont = fontDialog1.Font;
frm.richTextBox1.SelectionColor = fontDialog1.Color;
}
//Показываем форму
frm.Show();
}
private void mnuColor_Click(object sender, System.EventArgs e)
{
blank frm = (blank)this.ActiveMdiChild;
frm.MdiParent = this;
colorDialog1.Color = frm.richTextBox1.SelectionColor;
if (colorDialog1.ShowDialog() == DialogResult.OK)
{
frm.richTextBox1.SelectionColor = colorDialog1.Color;
}
frm.Show();
}
private void mnuFind_Click(object sender, System.EventArgs e)
{
//Создаем новый экземпляр формы FindForm
FindForm frm = new FindForm();
//Если выбран результат DialogResult.Cancel, закрываем форму (до этого
//мы использовали DialogResult.OK
if(frm.ShowDialog(this) == DialogResult.Cancel) return;
////Переключаем фокус на данную форму.
blank form = (blank)this.ActiveMdiChild;
////Указываем, что родительской формой является форма frmmain
form.MdiParent = this;
//Вводим переменную для поиска в определенной части текста —
//поиск слова будет осуществляться от текущей позиции курсора
int start = form.richTextBox1.SelectionStart;
//Вызываем предопределенный метод Find элемента richTextBox1.
form.richTextBox1.Find(frm.FindText, start, frm.FindCondition);
}
private void mnuAbout_Click(object sender, System.EventArgs e)
{
//Создаем новый экземпляр формы About
About frm = new About();
frm.Show();
}
private void toolBarMain_ButtonClick(object sender, System.Windows.Forms.ToolBarButtonClickEventArgs e)
{
//New
if (e.Button.Equals(tbNew))
{
mnuNew_Click(this, new EventArgs());
}
//Open
if (e.Button.Equals(tbOpen))
{
mnuOpen_Click(this, new EventArgs());
}
//Save
if (e.Button.Equals(tbSave))
{
mnuSave_Click(this, new EventArgs());
}
//Cut
if (e.Button.Equals(tbCut))
{
mnuCut_Click(this, new EventArgs());
}
//Copy
if (e.Button.Equals(tbCopy))
{
mnuCopy_Click(this, new EventArgs());
}
//Paste
if (e.Button.Equals(tbPaste))
{
mnuPaste_Click(this, new EventArgs());
}
}
}
}
using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.IO;
namespace NotepadCSharp
{
/// <summary>
/// Summary description for blank.
/// </summary>
public class blank : System.Windows.Forms.Form
{
public System.Windows.Forms.RichTextBox richTextBox1;
public string DocName = "";
private string BufferText = "";
private System.Windows.Forms.ContextMenu contextMenu1;
private System.Windows.Forms.MenuItem cmnuCut;
private System.Windows.Forms.MenuItem cmnuCopy;
private System.Windows.Forms.MenuItem cmnuPaste;
private System.Windows.Forms.MenuItem cmnuDelete;
private System.Windows.Forms.MenuItem menuItem6;
private System.Windows.Forms.MenuItem cmnuSelectAll;
public bool IsSaved = false;
private System.Windows.Forms.StatusBar statusBar1;
private System.Windows.Forms.StatusBarPanel sbAmount;
private System.Windows.Forms.StatusBarPanel sbTime;
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.Container components = null;
public blank()
{
InitializeComponent();
//Свойству Text панели sbTime устанавливаем системное время,
// конвертировав его в тип String
sbTime.Text = Convert.ToString(System.DateTime.Now.ToLongTimeString());
//В тексте всплывающей подсказки выводим текущую дату
sbTime.ToolTipText = Convert.ToString(System.DateTime.Today.ToLongDateString());
}
protected override void Dispose( bool disposing )
{
if( disposing )
{
if(components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}
region Windows Form Designer generated code
// Вырезание текста
public void Cut()
{
this.BufferText = richTextBox1.SelectedText;
richTextBox1.SelectedText = "";
}
// Копирование текста
public void Copy()
{
this.BufferText = richTextBox1.SelectedText;
}
// Вставка
public void Paste()
{
richTextBox1.SelectedText = this.BufferText;
}
// Выделение всего текста — используем свойство SelectAll элемента управления RichTextBox
public void SelectAll()
{
richTextBox1.SelectAll();
}
// Удаление.
public void Delete()
{
richTextBox1.SelectedText = "";
this.BufferText = "";
}
//Создаем метод Open, в качестве параметра объявляем строку адреса файла.
public void Open(string OpenFileName)
{
//Если файл не выбран, возвращаемся назад (появится встроенное предупреждение)
if (OpenFileName == "")
{
return;
}
else
{
//Создаем новый объект StreamReader и передаем ему переменную OpenFileName
StreamReader sr = new StreamReader(OpenFileName);
//Читаем весь файл и записываем его в richTextBox1
richTextBox1.Text = sr.ReadToEnd();
// Закрываем поток
sr.Close();
//Переменной DocName присваиваем адресную строку.
DocName = OpenFileName;
}
}
private void cmnuCut_Click(object sender, System.EventArgs e)
{
Cut();
}
private void cmnuCopy_Click(object sender, System.EventArgs e)
{
Copy();
}
private void cmnuPaste_Click(object sender, System.EventArgs e)
{
Paste();
}
private void cmnuDelete_Click(object sender, System.EventArgs e)
{
Delete();
}
private void cmnuSelectAll_Click(object sender, System.EventArgs e)
{
SelectAll();
}
//Создаем метод Save, в качестве параметра объявляем строку адреса файла.
public void Save(string SaveFileName)
{
//Если файл не выбран, возвращаемся назад (появится встроенное предупреждение)
if (SaveFileName == "")
{
return;
}
else
{
//Создаем новый объект StreamWriter и передаем ему переменную OpenFileName
StreamWriter sw = new StreamWriter(SaveFileName);
//Содержимое richTextBox1 записываем в файл
sw.WriteLine(richTextBox1.Text);
//Закрываем поток
sw.Close();
//Устанавливаем в качестве имени документа название сохраненного файла
DocName = SaveFileName;
}
}
private void blank_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
//Если переменная IsSaved имеет значение true, т. е. документ новый документ
//был сохранен (Save As) или в открытом документе были сохранены изменения (Save), то выполняется условие
if(IsSaved ==true)
//Появляется диалоговое окно, предлагающее сохранить документ.
if (MessageBox.Show("Do you want save changes in " + this.DocName + "?",
"Message", MessageBoxButtons.YesNo,
MessageBoxIcon.Question) == DialogResult.Yes)
//Если была нажата кнопка Yes, вызываем метод Save
{
this.Save(this.DocName);
}
}
private void richTextBox1_TextChanged(object sender, System.EventArgs e)
{
//Свойству Text панели sbAmount устанавливаем надпись "Аmount of symbols "
//и длину текста в RichTextBox.
sbAmount.Text = "Аmount of symbols " + richTextBox1.Text.Length.ToString();
}
}
}
Для получения официальных документов о завершении программы дополнительного профессионального образования (удостоверения о повышении квалификации, дипломов о профессиональной переподготовке и MBA) необходимо предоставить:
Внимание! Вы можете не заказывать доставку бумажной версии официального документы, а скачать его в электронном виде и распечатать самостоятельно. Информация о выданном документе в течение 1 месяца загружается в Федеральную информационную систему «Федеральный реестр сведений о документах об образовании и (или) о квалификации, документах об обучении» - ФИС ФРДО.
Доступ на новый сайт осуществляется с использованием адреса электронной почты, который был указан вами при регистрации на "старом". Мы постарались перенести все ваши данные с прежнего ресурса, однако не исключена вероятность потери части информации.
При возникновении проблемы со входом, воспользуйтесь функцией сброса пароля
Если вы обнаружите несоответствия, пожалуйста, сообщите нам.