При нажатии на Сумма в примере ArbitraryMethod из Лекция 7, VS 2013 выдается ошибка: Необработанное исключение типа "System.InvalidOperationException" в System.Windows.Forms.dll Дополнительные сведения: Недопустимая операция в нескольких потоках: попытка доступа к элементу управления "lblResult" не из того потока, в котором он был создан. Затем: Необработанное исключение типа "System.InvalidOperationException" в mscorlib.dll Дополнительные сведения: Для каждой асинхронной операции метод EndInvoke может вызываться только один раз. |
Работа с элементами управления
Сохранение файла при закрытии формы
Всякий раз, когда мы закрываем документ 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); } }2.7.
Запускаем приложение. При закрытии формы blank или frmmain появляется окно предупреждения (рис. 2.17):
OpenFileDialog и SaveFileDialog для SDI-приложений
При создании MDI-приложений приходится разделять код для открытия и сохранения файлов, как мы делали для приложения Notepad C#. В случае SDI-приложений весь код будет находиться в одном обработчике. Cоздаем новое приложение, называем его TextEditor. На форме размещаем элемент управления TextBox и устанавливаем следующие свойства:
Добавляем на форму элемент 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(); } }2.8.
Добавляем обработчик для пункта меню 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(); } }2.9.
Запускаем приложение. Как уже отмечалось, элемент управления TextBox имеет встроенное контекстное меню, поддерживает сочетание клавиш для редактирования, а диалоговые окна открытия и сохранения позволяют этому простейшему приложению работать с внешними файлами.
На диске, прилагаемом к книге, вы найдете приложение TextEditor (Code\Glava2\TextEditor).
FontDialog
Продолжим работу над приложением 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(); }2.10.
Запускаем приложение, и в окне Output появляется список ошибок (рис. 2.18).
В чем же дело? При расположении на форме blank элемента управления RichTextBox среда Visual Studio.NET сгенерировала экземпляр richTextBox1 класса System.Windows.Forms.RichTextBox с модификатором доступа private, из-за чего при обращении к нему и возникает исключение:
private System.Windows.Forms.RichTextBox richTextBox1;
Изменим модификатор на public и снова запустим приложение. При выборе пункта меню Font теперь можно менять параметры текущего текста.
ColorDialog
Диалоговое окно FontDialog содержит список цветов, которые могут быть применены к тексту, но предлагаемый список ограничен. Более интересной представляется возможность назначать пользовательский цвет, который может быть определен в большом диапазоне (рис. 2.19):
Из окна 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.