При выполнении в лабораторной работе упражнения №1 , а именно при выполнении нижеследующего кода: using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Text; using System.Windows.Forms; using Microsoft.Xna.Framework.Graphics;
namespace Application1 { public partial class MainForm : Form { // Объявим поле графического устройства для видимости в методах GraphicsDevice device;
public MainForm() { InitializeComponent();
// Подпишемся на событие Load формы this.Load += new EventHandler(MainForm_Load);
// Попишемся на событие FormClosed формы this.FormClosed += new FormClosedEventHandler(MainForm_FormClosed); }
void MainForm_FormClosed(object sender, FormClosedEventArgs e) { // Удаляем (освобождаем) устройство device.Dispose(); // На всякий случай присваиваем ссылке на устройство значение null device = null; }
void MainForm_Load(object sender, EventArgs e) { // Создаем объект представления для настройки графического устройства PresentationParameters presentParams = new PresentationParameters(); // Настраиваем объект представления через его свойства presentParams.IsFullScreen = false; // Включаем оконный режим presentParams.BackBufferCount = 1; // Включаем задний буфер // для двойной буферизации // Переключение переднего и заднего буферов // должно осуществляться с максимальной эффективностью presentParams.SwapEffect = SwapEffect.Discard; // Устанавливаем размеры заднего буфера по клиентской области окна формы presentParams.BackBufferWidth = this.ClientSize.Width; presentParams.BackBufferHeight = this.ClientSize.Height;
// Создадим графическое устройство с заданными настройками device = new GraphicsDevice(GraphicsAdapter.DefaultAdapter, DeviceType.Hardware, this.Handle, presentParams); }
protected override void OnPaint(PaintEventArgs e) { device.Clear(Microsoft.Xna.Framework.Graphics.Color.CornflowerBlue);
base.OnPaint(e); } } } Выбрасывается исключение: Невозможно загрузить файл или сборку "Microsoft.Xna.Framework, Version=3.0.0.0, Culture=neutral, PublicKeyToken=6d5c3888ef60e27d" или один из зависимых от них компонентов. Не удается найти указанный файл. Делаю все пунктуально. В чем может быть проблема? |
Работа с файлами и каталогами
Упражнение 7. Генератор случайных номеров
Иногда может потребоваться упорядоченный список номеров, сгенерированных случайным образом. В данном упражнении мы разработаем такую утилиту, используя рассмотренные классы работы с файлами. Номера будем размещать в текстовом файле. Настройку утилиты организуем через диалоговое окно, а для контроля процесса добавим консольный вывод.
- Добавьте к решению командой File/Add/New Project новый проект типа Windows Forms Application с именем App7 и назначьте его стартовым
- Командой Project/App7 Properties вызовите диалоговое окно настройки проекта и в выпадающем списке Output type вкладки Application установите значение Console Application
- Разработайте интерфейс диалогового окна в соответствии с таблицей свойств
Элемент | Свойство | Значение | Пояснения |
---|---|---|---|
Form | FormBorderStyle | FixedDialog | Фиксированный размер |
Size | 375; 385 | Ширина и высота окна | |
MaximizeBox | False | Скрыть системную кнопку | |
MinimizeBox | False | Скрыть системную кнопку | |
Text | Генератор случайных номеров | Заголовок окна | |
StartPosition | CenterScreen | Начальное положение | |
Font | Microsoft Sans Serif; 7,8pt | Родительский шрифт (по умолчанию) | |
Label | AutoSize | False | Подстройка размера под содержимое |
BackColor | Info | Цвет фона | |
Text | Генерирует список номеров случайным образом | Содержимое | |
Font | Arial; 12pt; style=Bold | Шрифт | |
ForeColor | Blue | Цвет текста | |
TextAlign | MiddleCenter | Центрирование текста | |
Location | 16; 8 | Позиция относительно клиентской области формы | |
Label | Text | Куда разместить файл: | |
Button | (Name) | btnDirTarget | Имя экземпляра кнопки |
Text | Browse | Метка кнопки | |
TextBox | (Name) | txtDirTarget | Путь к файлу |
Label | Text | Имя текстового файла: | Метка для txtFileName |
TextBox | (Name) | txtFileName | Текстовое поле для имени файла |
Text | ResultNumber.txt | Имя файла по умолчанию | |
Label | Text | Нижняя граница диапазона: | Текстовая метка |
TextBox | (Name) | txtMin | Текстовое поле для нижней границы генерируемых номеров |
Text | 0 | Значение по умолчанию | |
Label | Text | Постоянный шаг: | Текстовая метка |
TextBox | (Name) | txtStep | Дискрета приращения диапазона |
Text | 250 | Шаг по умолчанию | |
Label | Text | Количество точек: | Текстовая метка |
TextBox | (Name) | txtCount | Число генерируемых номеров |
Text | 2000 | Значение по умолчанию | |
Label | Text | Верхняя граница диапазона: | Метка |
TextBox | (Name) | txtMax | Расчет верхней границы |
Text | Пусто | ||
ReadOnly | True | Только для чтения | |
Button | (Name) | btnExecute | Кнопка выполнения |
Text | Execute | Метка кнопки |
Необязательно дословно следовать приведенной таблице, можно настроить окно и по своему. Главное, чтобы значимые элементы имели те же имена для согласованного управления в коде (который, я уверен, вами будет скопирован механически - программисты должны экономить свои силы, но лучше тогда, когда станут дорого стоить). При размещении элементов на форме важно следить за тем, чтобы они не были вложенными друг в друга, а каждый принадлежал только форме как своему ближайшему родителю.
- Запустите приложение - пользовательский интерфейс будет выглядеть так
Создадим и заполним обработчики элементов управления в процедурном коде файла Form1.cs.
- Добавьте в начало файла Form1.cs подключение библиотечного пространства имен System. IO для классов ввода-вывода
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Text; using System.Windows.Forms; // Подключение дополнительных пространств имен using System.IO;
- В режиме Design двойным щелчком на заголовке формы (или ином незанятом компонентами месте) создайте обработчик начальной загрузки и заполните его так
int min, step, count, max; FolderBrowserDialog dialogFolder = new FolderBrowserDialog(); private void Form1_Load(object sender, EventArgs e) { if (txtDirTarget.Text == String.Empty || Directory.Exists(txtDirTarget.Text) == false) { dialogFolder.RootFolder = System.Environment.SpecialFolder.MyComputer; dialogFolder.SelectedPath = ""; txtDirTarget.Text = String.Empty; } else { dialogFolder.SelectedPath = txtDirTarget.Text; } dialogFolder.Description = "Выберите место размещения текстового файла"; min = Convert.ToInt32(txtMin.Text); step = Convert.ToInt32(txtStep.Text); count = Convert.ToInt32(txtCount.Text); max = min + step * count; txtMax.Text = max.ToString(); }
За пределы функции вынесены поля-члены для их видимости в других обработчиках класса. В самом обработчике выполняется начальная инициализация этих переменных. Для выбора каталога используется стандартный диалог FolderBrowserDialog, который при запуске приложения устанавливается на вершину файловой системы компьютера, если выполняются указанные условия. Для явного преобразования типов используется библиотечный класс System.Convert.
- В режиме Design выделите кнопку btnDirTarget, откройте панель Properties, щелкните на пиктограмме Events, найдите событие Click и двойным щелчком на правой ячейке сетки свойств создайте обработчик, который заполните так
private void btnDirTarget_Click(object sender, EventArgs e) { dialogFolder.ShowDialog(); txtDirTarget.Text = dialogFolder.SelectedPath; }
Обработчик запускает диалог выбора папки, при закрытии которого путь сохраняется и отображается в текстовом поле txtDirTarget. Далее мы планируем этот путь использовать для создания текстового файла с именем из поля txtFileName. Выбранный путь записывается в поле.
Здесь есть одна тонкость. Текстовое поле может редактироваться пользователем и, таким образом, может содержать недостоверный путь. Можно, конечно, создавать каталог программно, если он не существует, но для тренировки мы просто заблокируем это поле для редактирования. Если присвоить txtDirTarget свойство ReadOnly=True, то оно будет серым и некрасивым. Другая возможность - просто запретить ввод символов в это поле, что мы сейчас и сделаем.
- Выделите текстовое поле txtDirTarget, в панели Properties установите режим Events и двойным щелчком на поле значений события KeyPress создайте обработчик со следующим кодом
private void txtDirTarget_KeyPress(object sender, KeyPressEventArgs e) { e.Handled = true; }
- Запустите приложение, выберите папку и попробуйте редактировать поле - стрелки и клавиша Delete продолжают функционировать
Добъем это поле окончательно.
- Выделите текстовое поле txtDirTarget, в панели Properties установите режим Events и двойным щелчком на поле значений события KeyDown создайте обработчик со следующим кодом
private void txtDirTarget_KeyDown(object sender, KeyEventArgs e) { e.Handled = true; }
- Запустите приложение - теперь поле полностью нередактируется, хотя и принимает курсор и фокус ввода
Таким образом, мы видим, что с помощью событий KeyDown и KeyPress можно контролировать пользовательский ввод в экземпляр текстового поля. Применим этот факт для фильтрации цифровых клавиш в текстовых полях txtMin, txtStep и txtCount, которые должны принимать только целые числа. Создадим для них общие обработчики, поскольку условие ограничения по вводу только цифр для них общее. Но прежде нам нужно узнать, в какой последовательности срабатывают события KeyDown и KeyPress.
- В режиме Design выделите (можно частично) с помощью лассо курсора (по русски - просто обведите, а используемое здесь словоблудие, чтобы привыкали к терминам) сразу 3 упомянутых текстовых поля и в панели Properties/Events задайте для них имена обработчиков, как показано на снимке
- Заполните созданные обработчики кодом вывода информации на консоль
private void txt_KeyDown(object sender, KeyEventArgs e) { Console.WriteLine("KeyDown"); } private void txt_KeyPress(object sender, KeyPressEventArgs e) { Console.WriteLine("KeyPress"); }
- Запустите приложение - получится последовательность
KeyDown KeyPress
Зная эту последовательность срабатывания, можно запрограммировать фильтр для пропуска только цифр.
- Заполните общие обработчики следующим кодом
bool isNumber; private void txt_KeyDown(object sender, System.Windows.Forms.KeyEventArgs e) { isNumber = e.KeyCode >= Keys.D0 && e.KeyCode <= Keys.D9 // keyboard - основная клавиатура || e.KeyCode >= Keys.NumPad0 && e.KeyCode <= Keys.NumPad9 // keypad - дополнительная клавиатура || e.KeyCode == Keys.Back; } private void txt_KeyPress(object sender, System.Windows.Forms.KeyPressEventArgs e) { // Запрещаем в текстовом поле лишние символы if (!isNumber) e.Handled = true; }
В первом обработчике формируется флаг isNumber, а во втором обработчике этот флаг используется для отфильтровывания цифр. Последовательность срабатывания событий обеспечивает нам нужный конвейер действий.
Создадим еще один обработчик, в котором 'на лету' будет пересчитываться значение последнего текстового поля txtMax по данным других полей. Но прежде добавим маркеры исходных текстовых полей в код начальной инициализации, чтобы в общем обработчике можно было их идентифицировать (различать) и индивидуально обрабатывать.
- Добавьте в функцию Form1_Load() следующий код
private void Form1_Load(object sender, EventArgs e) { ................................................... // Маркируем элементы для распознавания в общем обработчике txtMin.Name = "Min"; txtStep.Name = "Step"; txtCount.Name = "Count"; }
- В режиме Design выделите все три поля txtMin, txtStep и txtCount одновременно и создайте для них в панели Properties для события TextChanged общий обработчик с именем (нужно вручную ввести в поле) result_TextChanged, который заполните так
private void result_TextChanged(object sender, EventArgs e) { // Следим, чтобы редактируемое поле не оказалось пустым TextBox txtBox = (TextBox)sender;// Приводим ссылку к типу элемента if (txtBox.Text == String.Empty) { switch (txtBox.Name) { case "Min": txtMin.Text = "0"; break; case "Step": txtStep.Text = "0"; break; case "Count": txtCount.Text = "0"; break; } } // Конвертируем разными способами min = Convert.ToInt32(txtMin.Text); step = Int32.Parse(txtStep.Text); int.TryParse(txtCount.Text, out count); max = min + step * count; txtMax.Text = max.ToString(); }