При выполнении в лабораторной работе упражнения №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" или один из зависимых от них компонентов. Не удается найти указанный файл. Делаю все пунктуально. В чем может быть проблема? |
Редактирование данных OLE DB средствами ADO.NET
Упражнение 3. Полномасштабное редактирование одной таблицы
С динамическим созданием пользовательского интерфейса повозились, теперь в этом упражнении вновь частично вернемся к испытанному дедовскому способу визуального проектирования, который значительно легче, поскольку кодированием занимается дизайнер формы. А уж он-то намного больше знает, какой код правильно сгенерировать. Но все же мы программисты и тонкие настройки выполним сами. В этом упражнении я постарался их 'понатыкать' побольше.
На сей раз мы будем работать с таблицей Products готовой БД Northwind.mdb, потому что там есть столбец первичного ключа числового типа и удобно сделать этот столбец автозаполняющимся (AutoIncrement), чтобы не редактировать. В качестве элемента представления и редактирования данных применим объект DataGridView, который свяжем с загруженной таблицей, но не напрямую. Дело в том, что мы еще будем использовать объект-навигатор BindingNavigator, который обеспечит удобное перемещение по сетке DataGridView. Для обеспечения синхронной их работы с одной и той же таблицей, мы не сможем их сразу оба связать с ней. Но это можно легко сделать через объект-разветвитель BindingSource, к которому подключим таблицу, а уже через него подключим и другие объекты.
Этап визуального проектирования интерфейса
- Добавьте к решению ADO новый проект оконного приложения с именем WinForms3 и назначьте его стартовым
- В панели Solution Explorer курсором мыши перетащите каталог дата из предыдущего проекта WinForms2 на узел нового проекта WinForms3, мастеру настройки конфигурации скажите Cancel
-
В панели Solution
Explorer выделите файл БД Northwind.mdb и
в панели Properties установите для него
- Build Action=None
- Copy to Output Directory=Copy if newer
- Перетащите на форму из вкладки Data панели Toolbox объекты DataGridView, BindingNavigator, BindingSource. Проследите, чтобы объект BindingNavigator попал на форму, а не внутрь объекта DataGridView как дочерний (тогда лучше вначале перетащить BindingNavigator, а потом DataGridView )
- Настройте свойства объектов в соответствии с таблицей свойств. Имена экземпляров задайте в точности, иначе будет нестыковка с приведенным далее кодом
Объект | Свойство | Значение |
---|---|---|
Form | Text | Упражнение 3. |
Size | 333 ; 300 | |
DataGridView | (Name) | dataGridView |
Dock | Fill | |
BindingNavigator | (Name) | bindingNavigator |
CountItemFormat | из {0} | |
BindingSource | (Name) | bindingSource |
- Растяните форму по ширине раза в два, выделите сам объект bindingNavigator (можно щелкнуть на пиктограмме в самом низу рабочей области оболочки) и раскройте его интеллектуальный дескриптор (smart tag = смарт-тег) щелчком на маленьком квадратике с треугольничком в правом верхнем углу выделенного компонента
- Щелкните на ссылке Insert Standard Items окна смарт-тега, чтобы добавить ряд встроенных пиктограмм
- Из добавленных пиктограмм оставьте Save и Help, а остальные удалите
Лишние пиктограммы можно удалять по одной, выделяя их, а можно воспользоваться окном редактора Items Collection Editor.
- Щелкните в окне смарт-тега объекта bindingNavigator на ссылку Edit Items, чтобы открыть редактор элементов. Этот редактор с типовым интерфейсом и с ним легко работать
- Удалите лишние пиктограммы и добавьте сепаратор (разделитель) между кнопкой Save и предыдущими 'родными' пиктограммами навигатора
- Установите прежнюю ширину формы, прописанную в таблице свойств
В конечном итоге на этапе проектирования должен получиться такой интерфейс
Этап кодирования и настройки всего остального
Я приведу полный рабочий листинг кода, который получился не таким уж и большим, но какую функциональность он все-таки обеспечивает благодаря мощным библиотечным классам. Мы должны все же уважать за это Большого Била, хоть он и "проклятый загнивший капиталлист" (страшные слова, аж самому неприятно).
- Заполните файл Form1.cs проекта WinForms3 следующим кодом
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Text; using System.Windows.Forms; // Дополнительные пространства имен using System.Data.OleDb; using System.Data.Common; namespace WinForms3 { public partial class Form1 : Form { public Form1() { // Инициализировать созданное в режиме дизайнера InitializeComponent(); this.WindowState = FormWindowState.Maximized;// На полный экран // Создать все остатки от дизайнера и загрузить таблицу LoadProducts(); // Перед закрытием формы проверяем несохраненные изменения this.FormClosing += new FormClosingEventHandler(Form1_FormClosing); } // Проверяем при закрытии формы несохраненные изменения void Form1_FormClosing(object sender, FormClosingEventArgs e) { if(tableProducts.GetChanges() != null) { DialogResult result = MessageBox.Show("Вы не сохранили изменения в БД\nСохранить?", "Внимание!", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Warning); if (result == DialogResult.Yes) Update(); // Сохраняем данные else if (result == DialogResult.Cancel) e.Cancel = true;// Отменяем закрытие формы } } // Строка соединения к БД с абсолютным путем, определяемым сборкой String ConnectionString() { // Используем построитель строки подключения OleDbConnectionStringBuilder objConnectionStringBuilder = new OleDbConnectionStringBuilder(); objConnectionStringBuilder.Provider = "Microsoft.Jet.OLEDB.4.0"; objConnectionStringBuilder.DataSource = Application.StartupPath.ToString() + @"\Data\Northwind.mdb"; //Application.ExecutablePath + @"\Data\Northwind.mdb";// + имя сборки return objConnectionStringBuilder.ToString(); } // Выносим в поля для видимости в методах DataTable tableProducts; OleDbDataAdapter adapter; // Все загружаем и все настраиваем void LoadProducts() { // Загружаем таблицу Products целиком OleDbConnection connection = new OleDbConnection(ConnectionString()); adapter = new OleDbDataAdapter( new OleDbCommand("SELECT * FROM Products", connection)); tableProducts = new DataTable();// Имя можно не указывать! // Регистрируем обработчик события изменения поля таблицы для // выделения ячейки после редактирования через DataGridView tableProducts.ColumnChanged += new DataColumnChangeEventHandler(tableProducts_ColumnChanged); // Указать столбец с автозаполнением, но обязательно до включения в таблицу DataColumn col = new DataColumn("ProductID", typeof(int)); col.AutoIncrement = true; tableProducts.Columns.Add(col); col.ReadOnly = true;// Ключевой столбец не давать редактировать напрямую adapter.Fill(tableProducts);// Сам откроет соединение и сам закроет // Указать первичный ключ можно уже и в заполненной таблице // Синтаксис определения первичного ключа требует использовать массив // на случай, если в первичный ключ войдут несколько столбцов tableProducts.PrimaryKey = new DataColumn[] { tableProducts.Columns["ProductID"] }; // // Разветвитель, навигатор и сетку создали визуально // // Связали таблицу с разветвителем bindingSource.DataSource = tableProducts; // Поключили к разветвителю навигатор bindingNavigator.BindingSource = bindingSource; // Подключили к разветвителю элемент редактирования dataGridView.DataSource = bindingSource; // //Настраиваем DataGridView // // Сделаем ключевой столбец с автозаполнением только для чтения //dataGridView.Columns["ProductID"].ReadOnly = true;// Уже сделали в таблице // Ширина столбцов по ширине содержимого dataGridView.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.AllCells; dataGridView.RowHeadersWidth = 25;// Ширина первого (служебного) столбца //dataGridView.RowHeadersVisible = false;// Скрываем первый (служебный) столбец //dataGridView.Columns["ProductID"].Visible = false;// Скрываем рабочий столбец // Запретим выделение многих строк, все-равно // навигатор удаляет только по одной строке dataGridView.MultiSelect = false; // Настраиваем стиль строки заголовков сетки DataGridViewCellStyle columnHeaderStyle = new DataGridViewCellStyle();// Создали стиль columnHeaderStyle.BackColor = Color.Beige;// Цвет фона заголовка columnHeaderStyle.Font = new Font("Verdana", 10, FontStyle.Bold);// Шрифт columnHeaderStyle.Alignment = DataGridViewContentAlignment.MiddleCenter;// Выравнивать по центру столбца dataGridView.ColumnHeadersDefaultCellStyle = columnHeaderStyle;// Настроили и прицепили // Фоновый цвет всех ячеек таблицы по умолчанию белый. Но явно // задаем потому, что позже будем восстанавливать белым же цветом DataGridViewCellStyle defaultCellStyle = new DataGridViewCellStyle(); defaultCellStyle.BackColor = Color.White; dataGridView.DefaultCellStyle = defaultCellStyle;// Настроили и прицепили // // Настраиваем кнопки объекта BindingNavigator здесь // или в панели Properties дизайнера // bindingNavigatorMoveFirstItem.ToolTipText = "На первую запись"; bindingNavigatorMovePreviousItem.ToolTipText = "На предыдущую запись"; bindingNavigatorPositionItem.ToolTipText = "Текущая запись"; bindingNavigatorCountItem.ToolTipText = "Всего записей"; bindingNavigatorMoveNextItem.ToolTipText = "На следующую запись"; bindingNavigatorMoveLastItem.ToolTipText = "На последнюю запись"; bindingNavigatorAddNewItem.ToolTipText = "Добавить запись"; bindingNavigatorDeleteItem.ToolTipText = "Удалить запись"; saveToolStripButton.ToolTipText = "Сохранить изменения"; helpToolStripButton.ToolTipText = "Помощь"; helpToolStripButton.Enabled = false;// Затычка для Справки, пока не хотим... // Регистрируем обработчик события сохранения данных в БД saveToolStripButton.Click += new EventHandler(saveToolStripButton_Click); // // Создаем и настраиваем контекстное меню для дополнительных команд // // Создаем объект контекстного меню System.Windows.Forms.ContextMenuStrip menu = new ContextMenuStrip(); // Прицепляем к DataGridView dataGridView.ContextMenuStrip = menu; // Создаем объект команды и сразу с названием ToolStripMenuItem item = new ToolStripMenuItem("Восстановить"); // Всплывающая подсказка item.ToolTipText = "Откатить все несохраненные изменения"; // Добавляем команду в коллекцию команд контекстного меню menu.Items.Add(item); // Регистрируем обработчик команды для события Click item.Click += new EventHandler(item_RestoreClick); } // Список для хранения ячеек с измененными стилями // для последующего восстановления в ClearStyleModifiedCells() // (Ничего приличнее мне в голову не пришло! НаноСидоркин - помоги! // Надо искать оптовое решение в самом DataGridView) System.Collections.ArrayList listCell = new System.Collections.ArrayList(); // Срабатывает при модификации любого поля void tableProducts_ColumnChanged(object sender, DataColumnChangeEventArgs e) { DataGridViewCellStyle style = new DataGridViewCellStyle(); style.BackColor= Color.Aqua; dataGridView.CurrentCell.Style = new DataGridViewCellStyle(style); listCell.Add(dataGridView.CurrentCell);// Складываем ссылки для восстановления } // Обработчик команды контекстного меню void item_RestoreClick(object sender, EventArgs e) { // Если нечего откатывать if (tableProducts.GetChanges() == null) return; // Есть изменения, спрашиваем желание пользователя DialogResult result = MessageBox.Show("Вы действительно хотите откатить\n" + "последние несохраненные изменения?", "Внимание!", MessageBoxButtons.YesNo, MessageBoxIcon.Warning); if (result == DialogResult.Yes) { tableProducts.RejectChanges();// Откатываем таблицу ClearStyleModifiedCells(); // Снимаем выделение с ячеек } } // Сохраняем изменения в БД new void Update() { // Чтобы лишний раз не дергать проверку на уровне БД if (tableProducts.GetChanges() == null) return; // Создаем построитель команд по настройкам нашего адаптера OleDbCommandBuilder commandBuilder = new OleDbCommandBuilder(adapter); // Не реагировать на конфликты параллелизма, а записывать поверх commandBuilder.ConflictOption = ConflictOption.OverwriteChanges; // Отправить изменения таблицы в БД. Необходимые // команды генерирует созданный объект commandBuilder adapter.Update(tableProducts); } // Обработчик кнопки сохранения изменений в БД void saveToolStripButton_Click(object sender, EventArgs e) { // Проверка достоверности завершает редактирование текушего поля this.Validate(); bindingSource.EndEdit();// Останавливаем разветвитель Update();// Отправляем изменения в БД ClearStyleModifiedCells();// Восстанавливаем цвет ячеек сетки } // Все содержимое ArrayList имеет тип Object - надо явно приводить void ClearStyleModifiedCells() { // Снимаем выделение с измененных ячеек сетки DataGridViewCellStyle style = new DataGridViewCellStyle(); style.BackColor = Color.White; foreach (Object ob in listCell) { if (ob != null)// На случай, если строку с ячейками удалили! ((DataGridViewCell)ob).Style = new DataGridViewCellStyle(style); } listCell.Clear();// Очистить список, начать с чистого листа! } } }
- Запустите приложение, разберитесь с кодом, что не достроено - достройте, что недокрашено - докрасьте. Вот результат