Практическое занятие № 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 = 1AutoIncrementStep = 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;

}