Практическое занятие № 14
Тема: Отчеты по БД на основе шаблонов Word
Цель работы: получить практические навыки по формированию отчетов в программеMicrosoft Word
Ход работы
Пусть в СУБД 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.
Отображение данных из связанных таблиц
При выводе отчета о студентах одной из колонок будет колонка "Название группы", которой соответствует поле grupa из таблицы groups. Следовательно, нам нужно получать данные из двух связанных таблиц в одном наборе данных. Для этого создадим новый TableAdapter.
Щелкните правой кнопкой на пустом месте окна с таблицами и выберите команду "Добавить - Table Adapter". Введите текст запроса для связанного набора данных:
//отбираем все поля из таблицы stud и поле grupa из таблицы groups
SELECT students.*, groups.grupa FROM groups INNER JOIN students ON groups.id_grup = students.id_grup
Переименуйте созданную новую таблицу: Name = StudReport. В результате автоматически переименуется и связанный с таблицей TableAdapter в studReportTableAdapter.
Создайте программу для работы c БД:

Все поля в сетке назвать по-русски. Сетка заблокирована для ввода.
Указания: для формы задайте свойства: Caption=Поиск данных в БД, Position=DesktopCenter, Borderstyle=bsSingle (нерастягиваемая форма), MiximizeBox = false (нет кнопки разворачивания окна).
Для подключения связанного набора данных SotrReport нанесите на форму компонент DataRowView. Появится окно, в котором нужно указать подключаемую таблицу SotrReport. На форме появятся дополнительные компоненты для работы с таблицей: bazaDataSet - для доступа к подключению, studReportBindingSource - для работы со связанным набором данных, studReportTableAdapter - для работы с копией таблицы БД. Фамилии студентов будем отображать в алфавитном порядке. Для этого для компонента sotrReportBindingSource задайте свойство Sort = fam (имя поля для сортировки).
Для сетки задайте свойства: AllowUserToAddRows = false (запрет добавления новых строк в сетке), AllowUserToDeleteRows = false (запрет на удаление данных в сетке без подтверждения), AlternatingRowsDefaultCellStyle - BackColor = серый (цвет фона четных строк сетки), AutoSizeColumnsMode=Fill (ширина колонок подстраивается под размер сетки). Для настройки параметров колонок сетки откройте ее свойство Columns. Вы увидите список всех ее колонок. Колонки id_stud, id_grup, foto сделайте невидимыми (Visible=false), для остальных колонок в свойстве HeaderText укажите названия как на рисунке. Колонку "Группа" переместите так, как показано на рисунке.
Если запустить программу на выполнение, то сетка будет пустой, потому что в строке соединения мы не сохранили пароль к БД и подключение не установлено.
Для формы откройте событие Load. В этом событии будут находится вызов метода Fill(), загружающий копию связанного набора данных в компонент TableAdapter. Над этой командой добавьте команду подстановки пароля в строку соединения:
Properties.Settings.Default["BazaConnectionString"] += ";Jet OLEDB:Database Password=rpo";
Фото будем заполнять с помощью диалога выбора графического файла при щелчке на кнопке "+". Кнопка "-" очищает поле Фото.
Указания: добавьте компонент PictureBox.
Для связывания компонента с полем таблицы нужно в событии Load формы добавить команду:
pictureBox1.DataBindings.Add(new Binding("Image", studReportBindingSource, "foto", true));
Фото будем заполнять с помощью диалога. Нанесите на форму компонент OpenFileDialog и в свойстве Filter укажите допустимые форматы графических файлов:
Графические файлы|*.jpg;*.gif;*.bmp;*.png
Для кнопки "+" напишите код добавления фотографии:
void Button1Click(object sender, EventArgs e)
{
//если файл в диалоге выбран
if (openFileDialog1.ShowDialog()==DialogResult.OK)
{
//записываем файл в переменную
Bitmap pict = new Bitmap(openFileDialog1.FileName);
//в поле pictureBox отображаем переменную
pictureBox1.Image = (Image)pict;
}
}
Для кнопки "-" напишем код очистки фотографии:
void Button2Click(object sender, EventArgs e)
{
pictureBox1.Image=null;
}
Кнопка Анкета формирует отчет по текущей записи на основании созданного шаблона.
Указания: в папке с программой (откройте папку с проектом, а в ней папку Bin\Debug) создайте папку "Templates" для хранения шаблонов. Запустите Mіcrosoft Word, введите произвольный текст документа с текстовыми метками #fam#, #imya#, #otch#, #grupa#, #finance#, #datar#, #srbal#. Выделите созданную текстовую надпись #fam# (при выделении следите, чтобы не захватить символ конца строки), выполните команду Вставка - Закладка, введите имя закладки "fam" и щелкните на кнопке Добавить. Повторите создание закладок для каждой созданной текстовой метки шаблона.
Сохраните файл в папку "Templates". При этом в поле "Тип файла" укажите "Шаблоны Word 97-2003 ", а имя файла "Anketa".
Для формирования анкеты нанесите на форму кнопку Button. Задайте свойство Text = "Анкета".
Для работы с программой Microsoft Word вверху кода формы подключите пространства имен:
using Word = Microsoft.Office.Interop.Word;
using System.Reflection;
using System.Runtime.InteropServices;
Кроме этого нужно подключить COM библиотеку программы Microsoft Word. В контекстном меню проекта выберите команду "Добавить ссылку". В новом окне перейдите на закладку COM и выберите элемент с именем "Microsoft Word XX Object Library", где ХХ - номер версии Word (на разных К может быть разным).
Вверху класса формы опишите глобальную переменную:
Word.Application w;
Для кнопки напишите код вида:
void Button3Click(object sender, EventArgs e)
{
//пытаемся подключиться к запущенному Word
try
{
w = Marshal.GetActiveObject ("Word.Application") as Word.Application;
}
//если Word на запущен, запускаем его
catch (COMException err)
{
w = new Word.Application();
}
w.Documents.Add(Application.StartupPath + "\\templates\\anketa.dot");
//заменяем каждую закладку в шаблоне на поле текущей записи
w.ActiveDocument.Bookmarks["fam"].Range.Text=
(studReportBindingSource.Current as DataRowView)["fam"].ToString();
w.ActiveDocument.Bookmarks["imya"].Range.Text=
(studReportBindingSource.Current as DataRowView)["imya"].ToString();
w.ActiveDocument.Bookmarks["otch"].Range.Text=
(studReportBindingSource.Current as DataRowView)["otch"].ToString();
w.ActiveDocument.Bookmarks["grupa"].Range.Text=
(studReportBindingSource.Current as DataRowView)["grupa"].ToString();
w.ActiveDocument.Bookmarks["finance"].Range.Text=
(studReportBindingSource.Current as DataRowView)["finance"].ToString();
//дату рождения выведем без времени
//для этого дату нужно проверить на пустоту
//затем конвертировать в дату, а затем в текст
if ((studReportBindingSource.Current as DataRowView)["datar"].ToString()!="")
w.ActiveDocument.Bookmarks["datar"].Range.Text=
Convert.ToDateTime((studReportBindingSource.Current as DataRowView)["datar"]).ToString("dd/MM/yyyy");
w.ActiveDocument.Bookmarks["srbal"].Range.Text=
(studReportBindingSource.Current as DataRowView)["srbal"].ToString();
//делаем окно Word видимым
w.Visible=true;
}
Кнопка "Список" формирует в программе Microsoft Word документ со списком отобранных записей. При этом условия отбора задаются в полях внизу формы. Если условие не задано, то отчет формируется по всей таблице.
В конце таблицы добавляется новая строка. В первой ячейке отображается текст "Всего", а во второй ячейке - количество отобранных в отчете записей, в третьей - текст "Средний балл", в четвертой - значение среднего балла. Строка с рассчитанными значениями заливается произвольным цветом.
Указания: отчет будет формироваться по шаблону. Запустите Mіcrosoft Word, в текст документа введите произвольный текст- заголовок списка, а ниже создайте таблицу, которая состоит из 1 строки и 9 колонок. Данная строка будет играть роль шапки таблицы.
В ячейках шапки введите текст: № п/п, Фамилия, Имя, Отчество, Группа, Финансирование, Дата рожд., Средний балл, Фото. Если колонок много разверните лист в альбомную ориентацию. Укажите нужную ширину столбцов, задайте размер шрифта, выравнивание и другие параметры форматирования на ваше усмотрение. Сохраните файл в папку "Templates". При этом в поле "Тип файла" укажите "Шаблоны Word 97-2003 ", а имя файла "List".
Создание запроса для расчета количества сотрудников и среднего оклада для отчета
Для выполнения расчетов по таблицам БД создадим новый набор данных.
В окне "Источники данных" щелкните на кнопке "Изменить набор данных в конструкторе" для открытия списка таблиц. На пустом месте окна в контекстном меню выберите команду "Добавить - TableAdapter". Введите текст запроса для отбора записей из таблицы:
select count(*) as kolvo, avg(srbal) as sredbal from students
Переименуйте созданную новую таблицу: Name = CalcStud. В результате автоматически переименуется и связанный с таблицей TableAdapter в CalcStudTableAdapter.
Для подключения нового набора данных CalcStud нанесите на форму компонент DataRowView. Появится окно, в котором нужно указать подключаемую таблицу CalcStud. На форме появятся дополнительные компоненты для работы с таблицей: calcStudBindingSource - для работы с рассчитанным набором данных, calcStudTableAdapter - для работы с копией набора данных.
Перейдите в событие Load формы. Вы увидите, что в начале обработчика события, среда Visual Studio автоматически добавила вызов метода Fill() для нового набора данных. Перенесите эту команды после команды подстановки пароля в строку подключения к БД.
Проектирование панели для задания условия фильтрации
Для задания условий поиска нанесите на форму 3 текстовых поля TextBox.
Для отображения на форме процесса постройки отчета нанесите на форму компонент ProgressBar и задайте свойство Visible=false, Style = Continuous (плавное заполнение индикатора).
Нанесите на форму кнопку и задайте для нее свойство Text = Список. Для кнопки введите код:
void Button4Click(object sender, EventArgs e)
{
//вначале условие не задано
string s="";
//если первое поле не пустое, добавляем к условию
if (textBox1.Text!="")
s+="fam like '"+textBox1.Text+"%'";
//если второе поле не пустое, добавляем к условию
if (textBox2.Text!="")
if (s!="")
s+=" and imya like '"+textBox2.Text+"%'";
else
s+="imya like '"+textBox2.Text+"%'";
//если третье поле не пустое, добавляем к условию
if (textBox3.Text!="")
if (s!="")
s+=" and otch like '"+textBox3.Text+"%'";
else
s+="otch like '"+textBox3.Text+"%'";
//если условие задано
if (s!="")
{
//к набору данных из сетки применяем условие фильтрации
studReportBindingSource.Filter=s;
//для набора данных с расчетами добавляем условие
calcStudTableAdapter.Adapter.SelectCommand.CommandText="select count(*) as kolvo, avg(srbal) as sredbal from students where "+s;
}
//если условие не задано
else
{
//у набора данных из сетки отключаем фильтр
studReportBindingSource.Filter=null;
//для набора данных с расчетами убираем условие
calcStudTableAdapter.Adapter.SelectCommand.CommandText="select count(*) as kolvo, avg(srbal) as sredbal from students";
}
//обновляем набор данных с расчетными данными
calcStudTableAdapter.Fill(bazaDataSet.CalcStud);
//начинаем строить отчет
//переменные для чтения фото из БД
Byte[] blob = null;
MemoryStream memStream = null; //подключите System.IO
Image img =null;
//настраиваем начальные параметры индикатора
//начальное значение 0
progressBar1.Value = 0;
//максимальное значение равно количество записей в наборе
progressBar1.Maximum = studReportBindingSource.Count+1;
//делаем индикатор видимым
progressBar1.Visible = true;
//пытаемся подключиться к запущенному Word
try
{
w = Marshal.GetActiveObject ("Word.Application") as Word.Application;
}
//если Word на запущен, запускаем его
catch (COMException err)
{
w = new Word.Application();
}
w.Documents.Add(Application.StartupPath + "\\templates\\list.dot");
//увеличиваем индикатор на 1
progressBar1.Value++;
//счетчик картинок в документе
int k=0;
//счетчик строк в таблице (у нас в шаблоне имеется шапка, поэтому строк 1)
int i=1;
//в цикле проходим по набору данных StudReport
foreach(DataRowView row in studReportBindingSource)
{
//добавляем новую строку
w.ActiveDocument.Tables[1].Rows.Add();
//наращиваем количество строк
i++;
//в каждую ячейку i-й строки таблицы записываем значения поля запроса
w.ActiveDocument.Tables[1].Rows[i].Cells[1].Range.Text=(i-1).ToString();
w.ActiveDocument.Tables[1].Rows[i].Cells[2].Range.Text=row["fam"].ToString();
w.ActiveDocument.Tables[1].Rows[i].Cells[3].Range.Text=row["imya"].ToString();
w.ActiveDocument.Tables[1].Rows[i].Cells[4].Range.Text=row["otch"].ToString();
w.ActiveDocument.Tables[1].Rows[i].Cells[5].Range.Text=row["grupa"].ToString();
w.ActiveDocument.Tables[1].Rows[i].Cells[6].Range.Text=row["finance"].ToString();
//чтобы поле дата отображалось без времени
//выведем ее в нужном формате
//если дата не пустая
if (row["datar"].ToString()!="")
//выводим ее в формате без времени
w.ActiveDocument.Tables[1].Rows[i].Cells[7].Range.Text=
Convert.ToDateTime(row["datar"]).ToString("dd/MM/yyy");
//выводим средний балл
w.ActiveDocument.Tables[1].Rows[i].Cells[8].Range.Text=row["srbal"].ToString();
//выводим поле foto
//если поле foto не пустое
if (row["foto"].ToString()!="")
{
//считываем содержимое поля
blob = (byte[])row["foto"];
//выделяем в памяти буфер размером в поле foto
memStream = new MemoryStream(blob);
//считываем поле foto в буфер памяти
memStream.Write(blob, 0, blob.Length);
memStream.Position = 0;
//в переменную помещаем содержимое буфера памяти (конвертируем в графику)
img= Image.FromStream(memStream);
//копируем в буфер изображение
Clipboard.SetImage(img);
//в i-ю строку таблицы вставляем содержимое буфера
w.ActiveDocument.Tables[1].Rows[i].Cells[9].Range.Paste();
//наращиваем количество картинок
k++;
//для k-й картинки задаем ширину и высоту
w.ActiveDocument.InlineShapes[k].Width=50;
w.ActiveDocument.InlineShapes[k].Height=60;}
//увеличиваем индикатор на 1
progressBar1.Value++;
////переходим на следующую запись в наборе данных
}
//отображаем количество записей из набора данных CalcStud
//в таблицу отчета добавляем новую строку
w.ActiveDocument.Tables[1].Rows.Add();
//увеличиваем количество строк в таблице на 1
i++;
//в первой ячейке i-й строки отображаем текст "Всего"
w.ActiveDocument.Tables[1].Rows[i].Cells[1].Range.Text="Всего";
//во второй ячейке i-й строки отображаем значение
количества
w.ActiveDocument.Tables[1].Rows[i].Cells[2].Range.Text=(calcStudBindingSource.Current as DataRowView)["kolvo"].ToString();
//в третьей ячейке i-й строки отображаем текст "Всего"
w.ActiveDocument.Tables[1].Rows[i].Cells[3].Range.Text="Средний
балл";
//в
четвертой ячейке i-й строки отображаем значение
среднего оклада
w.ActiveDocument.Tables[1].Rows[i].Cells[4].Range.Text=(calcStudBindingSource.Current as DataRowView)["sredbal"].ToString();
//закрашиваем последнюю строку таблицы серым цветом
w.ActiveDocument.Tables[1].Rows[i].Shading.BackgroundPatternColor = Word.WdColor.wdColorGray25;
//отображаем документ для просмотра
w.Visible = true;
//индикатор скрываем
progressBar1.Visible=false;
}