Управление свойствами веб отчета внешними контролами

16.08.2017

В этой статье я хочу рассмотреть возможность работы с отчетом с помощью элементов управления веб формы в проекте ASP .Net MVC.

Итак, задача - создать веб приложение, которое будет позволять:

1)      загружать веб отчет;

2)      экспортировать отчет в один из трех форматов;

3)      отображать/скрывать панель инструментов веб отчета;

4)      настраивать стиль кнопок на панели инструментов;

5)      запускать отчет в Online дизайнере.

Приступим. Для начала проведем некоторые подготовительные работы, чтобы запустить веб отчет в MVC приложении. Добавляем ссылки на библиотеки: FastReport и FastReport.Web.

В папке Views->Shared нужно отредактировать файл _Layout.cshtml. Добавляем скрипты и стили в заголовок:

1
2
3
4
<head>
 @WebReportGlobals.Scripts()
 @WebReportGlobals.Styles()
</head>

Опять же в папке Views есть файл Web.config. Добавляем в него пространства имен:

1
2
3
4
 <namespaces>
 <add namespace="FastReport" />
 <add namespace="FastReport.Web" />
 </namespaces>

В корне проекта есть еще один Web.config. В него добавляем обработчик, сразу после секции modules:

1
2
3
4
5
6
 <modules>

 </modules>
 <handlers>
 <add name="FastReportHandler" path="FastReport.Export.axd" verb="*" type="FastReport.Web.Handlers.WebExport"/>
 </handlers>

В HomeController добавляем логику работы с отчетом.

В методе Index будем загружать отчет и передавать его во вью.

1
2
3
4
5
6
7
8
 public ActionResult Index()
 {
 SetReport();
 webReport.Width = Unit.Percentage(100);
 webReport.Height = Unit.Percentage(100);
 ViewBag.WebReport = webReport;
 return View();
 }

Я вынес загрузку отчета в отдельный метод, который мы рассмотрим ниже. Устанавливаем ширину и высоту веб отчета в 100%. С помощью ViewBag передаем отчет в представление. И возвращаем представление Index.

Чтобы использовать объект отчета в разных методах я создал глобальную переменную – экземпляр объекта WebReport.

1
public WebReport webReport = new WebReport();

1)  Теперь рассмотрим загрузку отчета:

1
2
3
4
5
6
7
8
private void SetReport()
 {
 string report_path = GetReportPath();
 System.Data.DataSet dataSet = new System.Data.DataSet();
 dataSet.ReadXml(report_path + "nwind.xml");
 webReport.Report.RegisterData(dataSet, "NorthWind");
 webReport.Report.Load(report_path + "Master-Detail.frx");
 }

Задаем путь к папке с отчетами. Для удобства я создал отдельный метод с присвоением переменной пути к отчетам. Далее, создаем экземпляр объекта DataSet. Загружаем в него базу данных XML. Затем, регистрируем источник данных в объекте отчета. И, наконец, загружаем шаблон отчета в объект WebReport.

Метод установки пути к папке с отчетами:         

1
2
3
4
private string GetReportPath()
 {
 return this.Server.MapPath("~/App_Data/");
 }

2)      Давайте, не переходя ко вью добавим еще метод выбора экспорта отчета:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public void ReportExport(string type)
 {
 SetReport();
 switch (type)
 {
 case "pdf":
 webReport.ExportPdf();
 break;
 case "csv":
 webReport.ExportCsv();
 break;
 default:
 webReport.ExportWord2007();
 break;
 }

Тут мы загрузили отчет. В зависимости от значения параметра type производим один из трех видов экспорта.

Теперь откроем представление Index.

Добавим на форму выпадающий список с тремя вариантами экспорта:

1
2
3
4
5
6
7
8
9
10
11
 @using (Html.BeginForm("ReportExport", "Home"))
 {
 @Html.DropDownList("Type", new List<SelectListItem>()
{
 new SelectListItem(){ Text= "PDF", Value = "pdf"},
 new SelectListItem(){ Text= "CSV", Value = "csv"},
 new SelectListItem(){ Text= "Word", Value = "doc"},
}, "Select export type")
 <input id="pdf" type="submit" value="Export" />
 }
@ViewBag.WebReport.GetHtml()

Здесь мы использовали html хэлпер, с помощью которого создали форму, указывающую на контроллер “Home” и экшен (метод) “ReportExport”. Помните, мы уже создали такой метод в контроллере. Внутри формы мы создаем элемент DropDownList и наполняем его значениями. Конечно, можно было создать модель данных. Но, так как список состоит всего из трех элементов, я заполнил его прямо в представлении. После выпадающего списка расположена кнопка типа submit, по которой будет обновляться веб страница.

Как вы помните, метод ReportExport принимает параметр type – значение из выпадающего списка. В зависимости от выбранного значения будет произведен экспорт отчета в соответствующий формат.

3)     Теперь реализуем сокрытие панели инструментов отчета. Во вью это будет выглядеть так:

1
2
3
4
@using (Html.BeginForm("Index", "Home"))
{
@Html.CheckBox("Toolbar", true, new { @onchange = "this.form.submit()" }) Toolbar
}

Как и в предыдущем примере, мы создаем форму. Однако, в этот раз указываем экшен Index – там, где у нас отображается отчет. Внутри формы мы создали элемент CheckBox. Его значение будем передавать в метод Index. На этот раз я решил не добавлять очередную кнопку для обновления страницы, а воспользовался событием @onchange, где указал функцию отправки формы "this.form.submit()". Теперь, при изменении значения checkbox страница будет обновляться.

По аналогии с экспортом отчета, мы должны передать в метод параметр. В данном случае это “Toolbar”. Будет передан строковый эквивалент булевой функции. Перейдем к нашему контролу, а именно к экшену Index:

1
2
3
4
5
6
7
8
9
10
11
12
13
public ActionResult Index(string toolbar)
 {
 SetReport();
 webReport.Width = Unit.Percentage(100);
 webReport.Height = Unit.Percentage(100);
 if (toolbar == "true")
 webReport.ShowToolbar = true;
 else
 webReport.ShowToolbar = false;
 
 ViewBag.WebReport = webReport;
 return View();
 }

В методе добавился один параметр и условие. В зависимости от значения параметра toolbar мы принимаем решение включать или отключать панель инструментов.

4)      Переходим к созданию элементов управления, с помощью которых мы сможем выбирать стиль иконок. В предыдущий пример с формой мы добавим еще четыре элемента RadioButton:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
@using (Html.BeginForm("Index", "Home"))
 {
 <table>
 <tr>
 <td>
 @Html.CheckBox("Toolbar", true, new { @onchange = "this.form.submit()" }) Toolbar
 </td>
 <tr>
 <tr>
 <td>Black Buttons:</td><td> @Html.RadioButton("Radio", "Black Buttons", true, new { style = "width: 13px;", @onchange = "this.form.submit()" })</td>
 </tr>
 <tr>
 <td>Green Buttons:</td><td> @Html.RadioButton("Radio", "Green Buttons", false, new { style = "width: 13px;", @onchange = "this.form.submit()" })</td>
 </tr>
 <tr>
 <td>Blue Buttons:</td><td>@Html.RadioButton("Radio", "Blue Buttons", false, new { style = "width: 13px;", @onchange = "this.form.submit()" })</td>
 </tr>
 <tr>
 <td>Red Buttons:</td><td>@Html.RadioButton("Radio", "Red Buttons", false, new { style = "width: 13px;", @onchange = "this.form.submit()" })</td>
 </tr>
 </table>
@ViewBag.WebReport.GetHtml()

 Для улучшения внешнего вида, я поместил элементы в таблицу. Рассмотрим один из элементов RadioButton:

Html.RadioButton("Radio", "Black Buttons", true, new { style = "width: 13px;", @onchange = "this.form.submit()" })

Здесь имя контрола – “Radio”. Именно так будет называться еще один параметр в экшене Index. Затем, следует значение – “Black Buttons”. То есть, на панели инструментов будут отображаться черные кнопки. Следующее значение – будет ли отмечена радио кнопка по умолчанию. Последний параметр представляет собой объект HtmlAttributes. Здесь можно указать любой из доступных атрибутов для тэга <input type="radio" />. Я воспользовался этим и указал ширину контрола и событие onchange по аналогии с предыдущим элементом checkbox.

Итак, всего четыре радио кнопки – четыре стиля иконок в панели инструментов. Вернемся к нашему экшену Index:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public ActionResult Index(string toolbar, string radio)
 {
 SetReport();
 webReport.Width = Unit.Percentage(100);
 webReport.Height = Unit.Percentage(100);
 if (toolbar == "true")
 webReport.ShowToolbar = true;
 else
 webReport.ShowToolbar = false;
switch (radio)
 {
 case "Red Buttons":
 webReport.ToolbarIconsStyle = ToolbarIconsStyle.Red;
 break;
 case "Green Buttons":
 webReport.ToolbarIconsStyle = ToolbarIconsStyle.Green;
 break;
 case "Blue Buttons":
 webReport.ToolbarIconsStyle = ToolbarIconsStyle.Blue;
 break;
 default:
 webReport.ToolbarIconsStyle = ToolbarIconsStyle.Black;
 break;
 }
 
 ViewBag.WebReport = webReport;
 return View();
 }

 Добавился еще один параметр – radio. В конструкции Switch я назначаю нужный стиль, в зависимости от значения radio.

Давайте вынесем обработку параметров toolbar и radio в отдельные методы, для порядка. 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public void ShowToolbar(string toolbar)
 {
 if (toolbar == "true")
 webReport.ShowToolbar = true;
 else
 webReport.ShowToolbar = false;
 }
 
 public void ToolbarStyle(string radio)
 {
 switch (radio)
 {
 case "Red Buttons":
 webReport.ToolbarIconsStyle = ToolbarIconsStyle.Red;
 break;
 case "Green Buttons":
 webReport.ToolbarIconsStyle = ToolbarIconsStyle.Green;
 break;
 case "Blue Buttons":
 webReport.ToolbarIconsStyle = ToolbarIconsStyle.Blue;
 break;
 default:
 webReport.ToolbarIconsStyle = ToolbarIconsStyle.Black;
 break;
 }
 }

Index тоже изменился:

1
2
3
4
5
6
7
8
9
10
public ActionResult Index(string toolbar, string radio)
 {
 SetReport();
 webReport.Width = Unit.Percentage(100);
 webReport.Height = Unit.Percentage(100);
ShowToolbar(toolbar);
 ToolbarStyle(radio);
 ViewBag.WebReport = webReport;
 return View();
 }

5)      Осталось реализовать последнюю задуманную функцию – запуск отчета в Online дизайнере. Скажу сразу, чтобы его отобразить, необходимо получить сборку OnlineDesigner с сайта разработчика и включить ее в проект. Просто разархивируйте и добавьте всю папку WebReportDesigner в корень проекта.

Добавим в форму из предыдущего примера кнопку и скрытое поле:

1
2
<input id="dsg" type="submit" value="@ViewBag.Result" onclick="document.getElementById('hid').value='@ViewBag.WebReport.DesignReport.ToString()'"/>
<input id="hid" type="hidden" name="dsg">

 По нажатию на кнопку будет отправлена форма. Обратите внимание, что атрибут value определяется через ViewBag. Мы передаем значение кнопки из контрола. Чуть позже вы поймете зачем я так сделал. Для кнопки назначено событие oncklick. В нем я присваиваю значение элементу hidden. Обратите внимание, что благодаря ViewBag я получаю значение свойства веб отчета. Таким образом, если на странице показан Дизайнер отчетов, то значение поля hidden будет ture, иначе false.

Для поля hidden задаем атрибут id=”hid”. Благодаря идентификатору мы находим нужный элемент на форме. Теперь весь код для представления выглядит так:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
@{
 ViewBag.Title = "Home Page";
}
<div style="float:left">
 @using (Html.BeginForm("ReportExport", "Home"))
 {
 @Html.DropDownList("Type", new List<SelectListItem>()
{
 new SelectListItem(){ Text= "PDF", Value = "pdf"},
 new SelectListItem(){ Text= "CSV", Value = "csv"},
 new SelectListItem(){ Text= "Word", Value = "doc"},
}, "Select export type")
 <input id="pdf" type="submit" value="Export" />
 }
 <div align="left">
 @using (Html.BeginForm("Index", "Home"))
 {
 <table>
 <tr>
 <td>
 @Html.CheckBox("Toolbar", true, new { @onchange = "this.form.submit()" }) Toolbar
 </td>
 <td>
 <input id="dsg" type="submit" value="@ViewBag.Result" onclick="document.getElementById('hid').value='@ViewBag.WebReport.DesignReport.ToString()'"/>
 <input id="hid" type="hidden" name="dsg">
 </td>
 <tr>
 <tr>
 <td>Black Buttons:</td><td> @Html.RadioButton("Radio", "Black Buttons", true, new { style = "width: 13px;", @onchange = "this.form.submit()" })</td>
 </tr>
 <tr>
 <td>Green Buttons:</td><td> @Html.RadioButton("Radio", "Green Buttons", false, new { style = "width: 13px;", @onchange = "this.form.submit()" })</td>
 </tr>
 <tr>
 <td>Blue Buttons:</td><td>@Html.RadioButton("Radio", "Blue Buttons", false, new { style = "width: 13px;", @onchange = "this.form.submit()" })</td>
 </tr>
 <tr>
 <td>Red Buttons:</td><td>@Html.RadioButton("Radio", "Red Buttons", false, new { style = "width: 13px;", @onchange = "this.form.submit()" })</td>
 </tr>
 </table>
 }
 </div>
</div>
 
 @ViewBag.WebReport.GetHtml()

 Перейдем к контроллеру.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public ActionResult Index(string toolbar, string radio, string dsg)
 {
 SetReport();
 webReport.Width = Unit.Percentage(100);
 webReport.Height = Unit.Percentage(100);
 ShowToolbar(toolbar);
 ToolbarStyle(radio);
 ViewBag.Result = ShowDesigner(dsg);
 ViewBag.WebReport = webReport;
 return View();
 }
 
 public string ShowDesigner(string dsg)
 {
 if (dsg == "False")
 {
 webReport.DesignReport = true;
 return "Show Report";
 }
 else if (dsg == "True")
 {
 webReport.DesignReport = false;
 return "Show Designer";
 }
 return "Show Designer";
 }

 Как видите добавился еще один параметр в методе Index. Его имя соответствует имени элемента hidden во вью. Также добавилась строка: «ViewBag.Result = ShowDesigner(dsg);».

В ней я передаю имя кнопки в представление. Новый метод ShowDesigner включает или отключает дизайнер отчета и возвращает имя кнопки.

Запустим приложение:

Выпадающий список с тремя видами экспорта:

 

Отключаем тулбар:

 

А теперь включим онлайн дизайнер отчетов:

 

Отобразим отчет и включим тулбар. Выберем какой-нибудь стиль для кнопок на тулбаре:

 

Таким образом, мы создали внешние элементы управления с помощью которых управляем свойствами объекта WebReport в приложении ASP .Net MVC. 

14 марта 2023

Будущее генерации отчетов с помощью Blazor WebAssembly

Пошаговая инструкция по созданию демо приложения на .NET 6 и 7 прямо в браузере с помощью Blazor WebAssembly в FastReport .NET.
14 февраля 2023

Как настроить веб-сервер Apache2 для FastReport .NET

Запускаем веб-сервер Apache2 в операционной системе Linux для FastReport .NET и .NET 5 с помощью нескольких простых команд.
12 июля 2022

Как отобразить много отчетов на одной странице в Blazor

Работа из кода Blazor-приложения для одновременного отображения различных отчётов с фильтрацией данных по условию пользователя.