|
При выполнении в лабораторной работе упражнения №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();// Очистить список, начать с чистого листа!
}
}
}-
Запустите
приложение, разберитесь с кодом, что не достроено - достройте,
что недокрашено - докрасьте. Вот результат


