Практическое занятие № 10

 

Тема: Приемы работы с сеткой

Цель работы: получить практические навыки по работе с сеткой и выполнению разных операций в ней

 

Ход работы

 

Пусть в СУБД Access спроектирована база данных (скачать). База защищена паролем "rpo" и имеет две таблицы.

 

Таблица "students", состоит из полей:

 

Имя поля Тип Размер
id_stud Счетчик Ключевое
fam Текстовый 15
imya Текстовый 15
otch Текстовый 15
finance Текстовый 10 (Госзаказ, Контракт)
datar Дата/время  
srbal Числовой Одинарной точности с плавающей точкой. Значение по умолчанию - 0
foto Поле OLE  
id_grup Числовой Внешний ключ для связи с таблицей groups

 

Таблица "groups", состоит из полей:

 

Имя поля

Тип

Размер

id_grup Счетчик Ключевое
grupa

Текстовый

30

 

В программе на C# выполните подключение базы данных

 

Указания: на панели "Источники данных" щелкните на кнопке "Добавить новый источник данных" (если панель не отображается, то выбери команду меню "Данные - Показать источники данных"). Запуститься мастер создания подключения к БД. В окне выберите значение "База данных", затем значение "Набор данных". На следующем шаге щелкните на кнопке "Создать подключение". В новом окне Вам будет предложено подключить файлы БД SQL Server. Щелкните на кнопке "Изменить" и выберите формат БД "Microsoft Access". После этого укажите нужный файл БД (путь к файлу не удаляйте, среда C# самостоятельно скопирует указанный файл в папку проекта и скорректирует путь к нему). Так как база защищена паролем, то щелкните на кнопке "Дополнительно" и в строке "Jet OLEDB: DataBase Password" укажите пароль "rpo". Для проверки соединения щелкните на кнопке "Проверить подключение". После задания всех параметров мастер предложит выбрать способ сохранения пароля к БД: не включать в строку подключения или включать в строку подключения. Выберите первый вариант для безопасности.

После задания параметров БД при переходе на следующий шаг мастера появится запрос на копирование файла БД в папку с проектом, подтвердите эту операцию.

На следующем шаге мастер предложит сохранить строку подключения в файл конфигурации приложения. Так как пароль доступа не включен в строку подключения, то можете согласиться на сохранение в файл.

На следующем шаге выберите обе таблицы students и groups, с которыми планируете работать в проекте, и щелкните "Готово".

Сразу нужно настроить поведение полей-счетчиков в таблицах. В окне "Источники данных" щелкните на кнопке "Изменить набор данных в конструкторе". Отобразится структура таблиц. Выделите поле id_stud в таблице students и измените свойства: AutoIncrementSeed = 1, AutoIncrementStep = 1. Выделите поле id_grup в таблице groups и измените свойства: AutoIncrementSeed = 1, AutoIncrementStep = 1.

 

Настройка корректного удаления новых записей

Если добавить новую запись в таблицу и сразу попытаться ее удалить, то часто появляется сообщение об ошибке, связанное с тем, что мастер подключения БД неправильно формирует команды на добавление, обновление и удаление данных. Для решения этой проблемы в окне со структурой таблиц щелкните правой кнопкой на строке "studentsTableAdapter" таблицы students, выберите команду "Настроить". В новом окне щелкните на кнопке "Дополнительно", в следующем окне выключите флажок "Использовать оптимистическую блокировку", щелкните ОК и Готово.

Повторите эти действия для таблицы groups.

 

Создайте программу для работы с данными таблицы. При этом форма должна иметь вид:

 

 

Указания: для формы задайте свойства: Text=Студенты, StartPosition=CenterScreen.

 

Для подключения таблицы students нанесите на форму компонент DataRowView. Появится окно, в котором нужно указать подключаемую таблицу students. На форме появятся дополнительные компоненты для работы с таблицей: bazaDataSet - для доступа к подключению, studentsBindingSource - для работы с набором данных, studentsTableAdapter - для работы с копией таблицы БД. Для сетки задайте свойства: AllowUserToAddRows = false (запрет добавления новых строк в сетке), ReadOnly=true, AllowUserToDeleteRows = false (запрет на удаление данных в сетке без подтверждения), AutoSizeColumnsMode=Fill (ширина колонок подстраивается под размер сетки),  RowHeadersWidth = 25 (уменьшаем ширину колонки с заголовками строк сетки).

Для настройки параметров колонок сетки откройте ее свойство Columns. Вы увидите список всех ее колонок. Колонку id_stud сделайте невидимой (Visible=false), для остальных колонок в свойстве HeaderText укажите названия как на рисунке, поле id_group разместите после поля datar и настройте свойство HeadetText="Группа".

Для выравнивания текста по центру в заголовках колонок сетки и во всех ее ячейках, для сетки задайте свойства: ColumnHeadersDefaultCellStyle.Alignment = MiddleCenter, DefaultCellStyle.Alignment = MiddleCenter. Для выравнивания текста по левому краю в колонке "Группа"  откройте свойство сетки Columns, выделите колонку "Группа" и задайте свойство DefaultCellStyle.Alignment = MiddleLeft.

В колонке "Ср.балл" можно вводить только числа. Для этого откройте свойство сетки Columns, выделите колонку "Ср.балл" и задайте свойство DefaultCellStyle.Format = числовой.

Для масштабирования размера сетки при изменении размера формы или раскрытия ее на весь экран привяжите края сетки в краям формы. Для этого в свойстве сетки Anchors активируйте все значения привязки (слева, справа, сверху, снизу).

 

Для подключения таблицы groups нанесите на форму компонент DataRowView. Появится окно, в котором нужно указать подключаемую таблицу groups. На форме появятся дополнительные компоненты для работы с таблицей: groupsBindingSource - для работы с набором данных, groupsTableAdapter - для работы с копией таблицы БД. Так как таблица groups не будет отображаться в сетке, а будет использоваться для выпадающего списка, то сетку удалите.

Если запустить программу на выполнение, то сетка будет пустой, потому что в строке соединения мы не сохранили пароль к БД и подключение не установлено.

Для формы откройте событие Load. В этом событии будут находится две команды Fill(), загружающие копии таблиц в компоненты TableAdapter. Над этими командами добавьте команду подстановки пароля в строку соединения:

 

Properties.Settings.Default["BazaConnectionString"] += ";Jet OLEDB:Database Password=rpo";

 

Добавим в правом нижнем углу формы под сеткой две кнопки. Одна для добавления новой записи, другая - для удаления.

 

Указания: для кнопок в свойстве Text задайте нужные надписи. Чтобы при изменении размеров формы кнопки всегда оставались в правом нижнем углу, привяжите каждую из них с помощью свойства Anchors, в котором включите нижний и правый край формы.

Для кнопки "Добавить" (button1) напишем код:

 

private void button1_Click(object sender, EventArgs e)

{

    //добавляем новый элемент в набор записей

    studentsBindingSource.AddNew();

    //кнопку добавления блокируем

    button1.Enabled = false;

}

 

Для кнопки "Удалить" (button2) напишем код:

 

 private void button2_Click(object sender, EventArgs e)

{

    //выдаем запрос на удаление

    //в тексте запроса указываем ФИО удаляемого студента

    //если пользователь подтвердил операцию (DialogResult.Yes) 

    if (MessageBox.Show("Удалить данные о студенте: "+

    (studentsBindingSource.Current as DataRowView)["fam"].ToString()+" "+

    (studentsBindingSource.Current as DataRowView)["imya"].ToString()+" "+

    (studentsBindingSource.Current as DataRowView)["otch"].ToString() + "?",

    "Подтвердите", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)

    {

        //удаляем текущую запись из набора данных  

        studentsBindingSource.RemoveCurrent();

        //обновляем изменения в таблице БД

        studentsTableAdapter.Update(bazaDataSet.students);

    }

}

 

Обычно в программах для работы с БД при переходе между строками сеток автоматически происходит сохранение изменений, если они имели место. В сетке dataGridView это возможность не реализована. Нужно обеспечить такое сохранение данных.

 

Указания: для набора данных studentsBindingSource в событии CurrentChanged введите код:

 

private void studentsBindingSource_CurrentChanged(object sender, EventArgs e)

{

    //если в наборе данных students имеются изменения

    if (bazaDataSet.students.GetChanges() != null)

    {

        //сохраняем их в таблице БД

        Validate();

        studentsBindingSource.EndEdit();

        studentsTableAdapter.Update(bazaDataSet.students);

    }

    //кнопку "Добавить" разблокируем

    button1.Enabled = true;

}

 

Реализуем сохранение изменений в БД не только при переходе по строкам сетки, но и при нажатии на Enter после завершения редактирования.

 

Указания: для реагирования на нажатия клавиш для формы задайте свойство KeyPreview = true.

Так как код сохранения изменений мы уже писали для события CurrentChanged набора данных studentsBindingSource, то в событии KeyUp формы вызовем этот обработчик, чтобы не писать одинаковый код несколько раз:

 

private void Form1_KeyUp(object sender, KeyEventArgs e)

{

    //если нажата клавиша Enter

    if (e.KeyCode == Keys.Return)

        //вызываем обработчик события перехода по записям набора данных

        studentsBindingSource_CurrentChanged(sender, e);

}

 

Выполните условной форматирование данных в сетке: записи без значения среднего балла окрасить белым цветом, отличники (со средним баллом 5) - светло-зеленым, хорошисты (со средним баллом от 4 и выше) - светло-синим, троечники (со средним баллом от 3 и выше) - светло-коралловым.

 

Указания: колонка, соответствующая полю srbal, имеет в сетке номер 7 (нумерация с 0, при подсчете нужно также учитывать первую невидимую колонку id_stud).

В событии RowPrePaint сетки введите код;

 

private void dataGridView1_RowPrePaint(object sender, DataGridViewRowPrePaintEventArgs e)

{

    //если 8-я колонка пуста (соответствует полю "srbal", нумерация с 0)

    if (dataGridView1.Rows[e.RowIndex].Cells[7].Value == DBNull.Value)

        //закрашиваем белым цветом

        dataGridView1.Rows[e.RowIndex].DefaultCellStyle.BackColor = Color.White;

    //если средний балл 5 (отличники)

    else if (Convert.ToDouble(dataGridView1.Rows[e.RowIndex].Cells[7].Value) ==5)

        //закрашиваем светло-зеленым цветом

        dataGridView1.Rows[e.RowIndex].DefaultCellStyle.BackColor = Color.LightGreen;

    //если средний балл от 4 и выше (хорошисты)

    else if (Convert.ToDouble(dataGridView1.Rows[e.RowIndex].Cells[7].Value) >= 4)

        //закрашиваем светло-синим цветом

        dataGridView1.Rows[e.RowIndex].DefaultCellStyle.BackColor = Color.LightBlue;

    //иначе (троечники)   

    else

        //закрашиваем светло-коралловым

        dataGridView1.Rows[e.RowIndex].DefaultCellStyle.BackColor = Color.LightCoral;

}

 

Для редактирования колонки "Дата рожд." будем использовать специальный тип колонки - DataGridViewCalendarColumn.

 

Указания: по умолчанию такой тип колонки в сетке отсутствует. Для его использования добавьте в проект файл класса этого типа колонки. Для этого в контекстном меню проекта выберите команду "Добавить - Существующий элемент" и укажите распакованный файл класса. После этого запустите проект для компиляции добавленного файла класса.

Для отображения календаря в колонке сетки откройте свойство сетки Columns и для колонки "Дата рожд." в свойстве ColumnType укажите тип DataGridViewCalendarColumn.

 

Для редактирования колонки "Финасирование" будем использовать выпадающий список, значения для которого строго фиксированы и не могут вводиться с клавиатуры.

 

Указания: для фиксированного списка можно задать нужный тип колонки в сетке. Откройте свойство Columns сетки, выберите колонку "Финансирование" и задайте свойство ColumnType = DataGridViewComboBoxColumn. В результате в колонке появится выпадающий список. Теперь в свойстве Items колонки введите допустимые значения: пустая строка, Госзаказ, Контракт. Чтобы выпадающий список появлялся только при входе в ячейку, задайте для колонки свойство DisplayStyle = Nothing.

 

Для редактирования колонки "Группа" будем использовать выпадающий список, значения для которого будут формироваться из таблицы-справочника "groups".

 

Указания: откройте свойство Columns сетки, выберите колонку "Группа"  и задайте свойство ColumnType = DataGridViewComboBoxColumn. В результате в колонке появится выпадающий список. Для связывания списка с таблицей справочником также для колонки задайте свойства: DataSource = groupsBindingSource, DisplayMember = grupa (названия групп будут отображаться в списке), ValueMember = id_grup (поле, по которому таблица-справочник связана с основной таблицей). Чтобы выпадающий список появлялся только при входе в ячейку, задайте для колонки свойство DisplayStyle = Nothing.

 

Поле foto нужно настроить так, чтобы изображение внутри ячейки масштабировалось автоматически.

 

Указания: откройте свойство Columns сетки, выберите поле foto и задайте свойство ImageLayout = Zoom.

 

При щелчке в поле с фотографией студента должна открываться вторая форма для редактирования изображения.

 

Указания: в событии CellClick сетки напишите код

 

void DataGridView1_CellClick(object sender, DataGridViewCellEventArgs e)

{

    //если щелкнули в 9 колонке (foto), но не на ее заголовке

    if (e.ColumnIndex==8 && e.RowIndex!=-1)

    {

        //отображаем форму Form2 (будет создана позже)

        Form2 form2 = new Form2();

        form2.ShowDialog();

    }

}

 

Вторая форма должна обращаться к источнику данных studentsBindingSource на главной форме. Для этого необходимо присвоить главной форме имя.

 

Указания: откройте файл проекта Program.cs внести изменения:

 

после описания класса программы

 

internal sealed class Program

 

введите описание глобальной переменной

 

public static Form1 form1;

 

Вместо строки

 

Application.Run(new Form1());

 

Вставить строки

 

Program.form1 = new Form1();

Application.Run(form1);

 

После этого обратится к главной форме можно будет по имени Program.form1. Также для обращения в коде второй формы к компоненту studentsBindingSource  измените для него уровень доступа, задайте свойство Modifiers = public.

 

Создадим форму для редактирования поля foto.

 

 

Указания:  добавьте новую форму и разместите на ней компонент PictureBox и 2 кнопки. Для формы задайте заголовок (Text), фиксированную границу (FormBorderStyle), отключите кнопки свернуть (MinimizedBox) и развернуть (MaximizedBox)  и размещение по центру главной формы при открытии (StartPosition=CenterParent).

Для связывания компонента pictureBox с полем foto в событии Load второй формы введите команду:

 

void Form2Load(object sender, EventArgs e)

{

    pictureBox1.DataBindings.Add(new Binding("Image", Program.form1.studentsBindingSource, "foto", true));

}

 

Фото будем заполнять с помощью диалога. Нанесите на форму компонент OpenFileDialog и в свойстве Filter укажите допустимые форматы графических файлов:

 

Графические файлы|*.jpg;*.gif;*.bmp;*.png

 

Для кнопки "+" напишите код добавления фотографии:

 

void Button1Click(object sender, EventArgs e)

{

    //если файл в диалоге выбран

    if (openFileDialog1.ShowDialog()==DialogResult.OK)

    {        

        //в поле pictureBox отображаем выбранный файл

        pictureBox1.Image = Image.FromFile(openFileDialog1.FileName);

    }

}

 

Для кнопки "-" напишем код очистки фотографии:

 

void Button2Click(object sender, EventArgs e)

{

    pictureBox1.Image=null;

} 

 

Реализуем в программе возможность настройки и сохранения пути к файлу БД. В качестве способа хранения пути к БД будем использовать файл конфигурации приложения.

 

Указания: в структуре проекта откройте файл Properties\Setting.settings. В открывшейся таблице со списком параметров добавьте новый: имя = path, тип = string, область = Пользователь.

Внесите в код события Load главной формы изменения. Вместо добавления к строке подключения пароля БД введите фрагмент вида:

 

private void Form1_Load(object sender, EventArgs e)

{

//описываем переменную для хранения пути к БД

//и считываем в нее значение параметра path

string path = Properties.Settings.Default["path"].ToString();

//если считанный в переменную путь к файлу не существует

if (!File.Exists(path))

    //открываем диалог выбора БД

    if (openFileDialog1.ShowDialog() == DialogResult.OK)

    {

        //записываем новый путь в переменную

        path = openFileDialog1.FileName;

        //сохраняем значение переменной в параметр path

        Properties.Settings.Default["path"] = path;

        Properties.Settings.Default.Save();

    }

    //если пользователь отказался от выбора БД

    else

        //завершаем работу приложения

        Application.ExitThread();

//настраиваем параметры подключения

//параметру "sotrConnectionString" присваиваем строку подключения

//вместо имени БД подставляем переменную path

Properties.Settings.Default["sotrConnectionString"] = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + path + ";Jet OLEDB:Database Password=123";

//отображаем главную форму поверх остальных окон

TopMost = true;

TopMost = false;

 

//дальше команды Fill() для загрузки данных из таблиц БД

. . .

 

Для проверки запустите программу на выполнение, указав путь к БД. Закройте программу.

Переименуйте файл БД и запустите программу еще раз. Должен снова появиться диалог выбора файла БД.