При нажатии на Сумма в примере ArbitraryMethod из Лекция 7, VS 2013 выдается ошибка: Необработанное исключение типа "System.InvalidOperationException" в System.Windows.Forms.dll Дополнительные сведения: Недопустимая операция в нескольких потоках: попытка доступа к элементу управления "lblResult" не из того потока, в котором он был создан. Затем: Необработанное исключение типа "System.InvalidOperationException" в mscorlib.dll Дополнительные сведения: Для каждой асинхронной операции метод EndInvoke может вызываться только один раз. |
Справочные материалы. перевод приложений. специальные возможности
Пользовательский выбор языка. Перевод сообщений приложения
В рассмотренном примере меняется пользовательский интерфейс, представляющий собой значения свойства Text элементов управления. Между тем в приложениях используются текстовые сообщения, определяемые в коде, например, в "Работа с элементами управления" в приложении Notepad C# при попытке закрыть измененный документ появлялось окно-предупреждение Do you want save changes in NameDocument?. Рассмотрим перевод сообщений приложения и пользовательское изменение интерфейса. Скопируем проект TextEditor из "Работа с элементами управления" . В классе формы добавляем переменные для сохранения документа:
public bool IsSaved = false; public string fileName;
Создаем метод Save, в который вставляем вырезанный обработчик пункта меню mnuSave:
public void Save(object sender, System.EventArgs e) { //Показываем диалог выбора файла saveFileDialog1.ShowDialog(); // В качестве имени сохраняемого файла устанавливаем переменную fileName 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(); IsSaved = true; } }Листинг 8.1.
В обработчике меню mnuSave вызываем этот метод:
private void mnuSave_Click(object sender, System.EventArgs e) { this.Save( fileName, e); }
Добавляем обработчик события Closing формы:
private void Form1_Closing(object sender, System.ComponentModel.CancelEventArgs e) { //Если переменная IsSaved имеет значение true, т. е. документ новый документ //был сохранен (Save As) или в открытом документе были сохранены изменения (Save), то выполняется условие if(IsSaved ==true) //Появляется диалоговое окно, предлагающее сохранить документ. if (MessageBox.Show("Do you want to save changes in this document?", "Message", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes) //Если была нажата кнопка Yes, вызываем метод Save { this.Save( fileName, e); } }Листинг 8.2.
Запускаем приложение. Теперь при попытке закрыть измененный документ появляется окно-предупреждение. Закрываем приложение, переключаемся в режим дизайна и добавляем следующие пункты меню (рис. 8.27):
Устанавливаем свойству Localizable формы значение True, в свойстве Language выбираем язык English (United States). Компилируем приложение, в свойстве Language выбираем язык Russian (Russia). Переводим пункты меню на русский язык:
Name | Text |
mnuFile | &Файл |
mnuOpen | &Открыть |
mnuSave | &Сохранить |
mnuLanguage | &Язык |
mnuEnglish | &English |
mnuRussian | &Русский |
В окне Solution Explorer щелкаем правой кнопкой на названии проекта TextEditor и добавляем новый файл — Add/Add New Item… . В появившемся окне выбираем шаблон Assembly Resource File и называем его ClosingText.en-US.resx (рис. 8.28).
Проделаем эту операцию еще раз, новый шаблон назовем ClosingText.ru-RU.resx. Мы добавили эти файлы для хранения в них текстовых переменных, используемых приложением для различных локализаций. Откроем ресурс ClosingText.en-US.resx и введем переменную MessageText, в значении value которой укажем текст Do you want to save changes in this document?, выводимый приложением при закрытии (рис. 8.29).
Аналогично, в ресурсе ClosingText.ru-RU.resx создадим такую же переменную, в значении которой укажем текст на русском языке: "Вы хотите сохранить изменения в документе?" (рис. 8.30).
Переходим в код формы, подключаем следующие пространства имен:
//Пространство имен, используемое для определения культуры //приложения и операционной системы using System.Globalization; //Пространство, используемое для работы с файлами ресурсов .resx, //такими как ClosingText.en-US.resx, ClosingText.ru-RU.resx. using System.Resources; //Пространство для работы со сборками, более подробно о них см. лекцию 9. using System.Reflection; using System.Threading;
В классе формы объявляем следующие переменные и объекты:
//Переменная выбора, необходимая для определения культуры public string CultureDefine; //Переменная для хранения английской культуры private string EnglishCulture; //Переменная для русской культуры. private string RussianCulture;
Для управления ресурсами используется класс ResourceManager, который позволяет извлекать значения переменных, созданных в файле-ресурсе. Общая схема использования этого класса:
ResourceManager resourceManager = new ResourceManager ("ПространствоИмен.НазваниеРесурса", Assembly.GetExecutingAssembly());
Для использования извлекаемой строковой переменной обращаемся к ее имени в ресурсе:
MessageBox.Show(resourceManager.GetString("ИмяПеременнойвРесурсе");
Возвращаемся к нашему листингу:
//Создаем экземпляр resourceManager класса ResourceManager ResourceManager resourceManager;