Перейти к содержанию

Scripts: различия между версиями

Материал из Химсофт Вики
 
(не показано 58 промежуточных версий этого же участника)
Строка 1: Строка 1:
==Общие сведения==
'''Вкладка <code>Код</code>''' – содержит программу на языке высокого уровня, которая является частью отчета.


Раздел <code>Scripts</code> предназначен для добавления программной логики непосредственно в файл макета отчета.
Программа может быть написана на одном из языков <code>.NET</code>:
*'''<code>C#</code>''' (предпочтительно);
*<code>VisualBasic.NET</code> (нежелательно).


Это позволяет отчету быть самодостаточным: код из раздела выполняется в процессе формирования отчета.
Область применения вкладки <code>Код</code> довольно обширна - она позволяет:
*выполнить обработку данных, которую невозможно сделать штатными средствами ядра дизайнера;
*управлять печатью страниц отчета и бэндов на странице;
*управлять взаимодействием элементов управления на диалоговых формах;
*управлять формированием динамических объектов <code>Таблица</code>;
*и многое другое.


Внутри раздела можно создавать собственные вспомогательные функции для выполнения сложных вычислений прямо «на лету».
Чтобы увидеть код отчета, переключитесь на закладку <code>Код</code> в дизайнере:


==GetOrDash()==
[[Файл: code_obj_1.png | center | border]]
Функция <code>GetOrDash()</code> - предназначена для обработки пустых значений (<code>NULL</code>, пустые строки, пробелы) в ячейках отчета.  


Она гарантирует, что вместо пустого места в таблице всегда будет отображаться визуальный маркер <code>-</code> (''дефис''), что улучшает читаемость документа.
Язык для вкладки <code>Код</code> настраивается в меню <code>Отчет|Свойства...</code>.  


<syntaxhighlight lang="vb">
Делать это желательно сразу после создания нового отчета, так как при смене языка существующий код очищается.
Public Function GetOrDash(field As Object) As String
 
If field Is Nothing OrElse IsDBNull(field) OrElse String.IsNullOrEmpty(field.ToString().Trim()) Then
[[Файл: code_obj_2.png | center | border]]
Return "-"
 
End If
==Общая информация==
   
 
Return field.ToString()
Вкладка <code>Код</code> в дизайнере содержит только то, что написано вами.
End Function
 
</syntaxhighlight>
===Во вкладке можно===
*добавить в главный класс кода свои переменные, методы, свойства;
*создать обработчики событий объектов отчета;
*добавлять новые классы, если это необходимо (класс может быть добавлен как перед главным классом <code>ReportScript</code>, так и после него.
 
===Во вкладке нельзя===
*удалять, переименовывать или изменять область видимости главного класса <code>ReportScript</code>;
*переименовывать пространство имен, в котором находится главный класс.
 
===Порядок действий дизайнера при запуске отчета===
*дизайнер добавляет в код список переменных, имена которых совпадают с именами объектов отчета; это делается перед компиляцией кода и позволяет обращаться к объектам отчета по их имени;
*в код добавляются выражения, имеющиеся в отчете, в виде функций;
*выполняется компиляция кода, если главный класс не пустой;
*инициализируются переменные, которые были неявно добавлены в код;
*обработчики событий, определенные в коде, привязываются к объектам отчета;
*запускается отчет.
 
==Обработчики событий==
 
===Создание обработчика события===
*выделить нужный объект;
*в окне <code>Свойства</code> нажать кнопку [[Файл: event_btn.png|border]], чтобы переключиться на список событий:


===Входные параметры===
[[Файл: event_handler_1.png|border|center]]
*<code>field</code> (''Object'') - данные из поля набора данных (принимает любой тип данных, так как параметр объявлен как <code>Object</code>).


===Выходные данные===
*выбрать интересующее событие и сделать на нем двойной щелчок мышью - дизайнер добавит в код отчета пустой обработчик события:
* <code>String</code> - строковое представление данных, если поле содержит значимую информацию;
* <code>-</code> (''дефис'') - если входной параметр:
**равен <code>Nothing</code> (не инициализирован);
**равен <code>DBNull.Value</code> (пустое значение из базы данных);
**является пустой строкой <code>""</code>;
**содержит только пробелы (метод <code>.Trim()</code>).


==GetOr()==
<syntaxhighlight lang="C#">
private void Text2_BeforePrint(object sender, EventArgs e)
{


<syntaxhighlight lang="vb">
}
Public Function GetOr(field As Object,
Optional swap As String = "",
Optional pref As String = "",
Optional suf As String = "") As String
   
If field Is Nothing OrElse IsDBNull(field) OrElse String.IsNullOrWhiteSpace(field.ToString()) Then
Return swap
End If
   
Return pref & field.ToString().Trim() & suf
End Function
</syntaxhighlight>
</syntaxhighlight>


===Входные параметры===
===Удаление обработчика события===
*<code>field</code> (''Object'') - проверяемое поле (может быть числом, строкой или объектом базы данных);
*выбрать событие в окне <code>Свойства</code>;
*<code>swap</code> (''String'', необязательно) - значение «подмены», которое вернется, если поле пустое; по умолчанию — пустая строка;
*выделить текст имени события и нажамть клавишу <code>Delete</code>:
*<code>pref</code> (''String'', необязательно) - префикс, который добавится перед значением;
*<code>suf</code> (''String'', необязательно) - суффикс, который добавится после значения.


===Выходные данные===
[[Файл: event_handler_2.png|border|center]]
*<code>String</code> - отформатированная строка с префиксом и суффиксом, либо значение <code>swap</code>;


===Алгоритм===
==События==
*проверка на пустоту - функция проверяет объект <code>field</code> на три условия: равен ли он <code>Nothing</code>, является ли он <code>DBNull</code> (пустота из базы данных) или состоит ли он только из пробелов;
*обработка пустого значения - если хотя бы одно условие истинно, возвращается значение параметра <code>swap</code>;
*форматирование - если поле содержит данные, функция обрезает лишние пробелы по краям (<code>Trim</code>), добавляет к нему заданные префикс (<code>pref</code>) и суффикс (<code>suf</code>) и возвращает результат.


==ConcatFields()==
Каждый объект отчета имеет несколько '''событий''', которым можно назначить '''обработчик''' – метод из вкладки кода.


Функция <code>ConcatFields()</code> - предназначена для объединения нескольких текстовых значений в одну строку с использованием заданного разделителя.  
Чтобы максимально гибко управлять отчетом, нужно:
*четко представлять, в какой момент времени вызывается каждое из событий;
*использовать те события, которые соответствуют поставленной задаче.


<syntaxhighlight lang="vb">
===Пример===
Public Function ConcatFields(separator As String, ParamArray fields() As Object) As String
Рассмотрим процесс формирования отчета и события, которые при этом генерируются.  
If fields Is Nothing Then Return "-"
   
Dim list As New System.Collections.Generic.List(Of String)
   
For Each f As Object In fields
If f Is Nothing Then Continue For
Dim elem As String = f.ToString().Trim()
If String.IsNullOrEmpty(elem) Then Continue For
list.Add(elem)
Next
   
If list.Count = 0 Then
Return "-"
Else
Return String.Join(separator, list.ToArray())
End If
End Function
</syntaxhighlight>


===Входные параметры===
В качестве примера возьмем простой отчет, содержащий одну страницу, один бэнд <code>Данные</code> и два объекта <code>Текст</code> на бэнде:
*<code>separator</code> (''String'') - символ или текст, который будет стоять между элементами (например - запятая, или пробел, или перенос на следующую строку);
*<code>ParamArray fields()</code> (''Object'') - список аргументов любого количества, перечисляется через запятую (также можно передать массив).


===Выходные данные===
[[Файл: events_1.png|center|border]]
*<code>String</code> - одна строка из объединенных элементов.
*<code>-</code> (''дефис'') - если данных нет.


===Алгоритм===
===Порядок событий===
*<code>If fields Is Nothing Then Return "-"</code> - если массив аргументов вообще не передан, функция сразу возвращает дефис;
#В начале отчета вызывается событие <code>StartReport</code> объекта <code>Отчет</code>.
*<code>Dim list As New System.Collections.Generic.List(Of String)</code> - создается временный список для хранения "чистых" строковых элементов;
#Перед формированием страницы вызывается событие страницы <code>StartPage</code>. Это событие вызывается один раз для каждой страницы шаблона отчета (не путать со страницами готового отчета!). В нашем случае, сколько бы ни было страниц в готовом отчете – событие вызовется один раз, т.к. шаблон отчета состоит из одной страницы.
*<code>For Each f As Object In fields</code> - цикл по каждому полученному на входе значению;
#Затем вызывается событие <code>CreatePage</code>, которое происходит как раз в тот момент, когда страница создается в подготовленном отчете.
*<code>If f Is Nothing Then Continue For</code> - если текущий элемент пуст (null), он пропускается;
#Далее начинается печать строк бэнда <code>Данные</code>. Происходит это следующим образом:
*<code>Dim elem As String = f.ToString().Trim()</code> - значение переводится в строковый элемент и очищается от лишних пробелов по краям;
#::4.1 вызывается событие бэнда <code>BeforePrint</code>;
*<code>If String.IsNullOrEmpty(elem) Then Continue For</code> - если после удаления пробелов строковый элемент оказался пустым, он пропускается;
#::4.2 вызываются события <code>BeforePrint</code> всех объектов, лежащих на бэнде;
*<code>list.Add(elem)</code> - корректный строковый элемент добавляется в итоговый список;
#::4.3 все объекты заполняются данными;
*<code>If list.Count = 0 Then Return "-"</code> - если после проверки всех элементов список пуст (все было null или пробелы), возвращается дефис;
#::4.4 вызываются события <code>AfterData</code> всех объектов, лежащих на бэнде;
*<code>Return String.Join(separator, list.ToArray())</code> - все накопленные в списке элементы склеиваются в одну строку через указанный разделитель.
#::4.5 вызывается событие бэнда <code>BeforeLayout</code>;
#::4.6 происходит размещение объектов на бэнде (если среди них есть растягиваемые объекты) и подсчет высоты бэнда и его растягивание (если бэнд растягиваемый);
#::4.7 вызывается событие бэнда <code>AfterLayout</code>;
#::4.8 если бэнд не помещается на свободном месте страницы, формируется новая страница;
#::4.9 бэнд и все его объекты выводятся на страницу готового отчета;
#::4.10 вызывается событие <code>AfterPrint</code> бэнда;
#::4.11 вызывается событие <code>AfterPrint</code> всех объектов бэнда.
#Печать строк бэнда происходит до тех пор, пока есть данные в источнике.
#После этого формирование отчета в нашем случае завершается и вызываются события <code>FinishPage</code> страницы отчета...
#...и наконец – событие <code>FinishReport</code> объекта <code>Отчет</code>.


==GetExperience()==
===Выводы===
*используя события разных объектов, можно контролировать практически каждый момент формирования отчета;
*большинство действий можно выполнить, используя только событие бэнда <code>BeforePrint</code> – любые изменения, внесенные в объект, будут тут же отображены;
*в событии <code>BeforePrint</code> невозможно анализировать, на какой странице будет напечатан бэнд, если он растягиваемый – ведь подсчет высоты бэнда будет выполнен в пункте <code>4.6</code>;
*определить номер страницы для растягиваемого бэнда можно с помощью следующих событий
::*<code>AfterLayout</code> в пункте <code>4.7</code>;
::*<code>AfterPrint</code> в пункте <code>4.10</code> (правда, в этом случае бэнд уже будет напечатан и действия над объектами ничего не дадут).


Функция <code>GetExperience()</code> рассчитывает и форматирует строку о стаже работы сотрудника на основе даты получения диплома.  
==Обращение к объектам .NET==
===Сборки по умолчанию===
Из вкладки кода можно обращаться к любым объектам <code>.NET</code>, которые определены в сборках, подключаемых к новому отчету по умолчанию.  


Она выводит количество лет с правильным суффиксом (через вспомогательную функцию <code>YearsWithSuffix</code>) и указывает временной интервал от даты диплома до сегодняшнего дня.
На момент создания описания к ним относятся:


<syntaxhighlight lang="vb">
<syntaxhighlight lang="C#">
Public Function GetExperience(diplomDate As Object) As String
System.dll
If IsDBNull(diplomDate) OrElse diplomDate Is Nothing Then
System.Xml.dll
Return "-"
System.Data.dll
End If
System.Drawing.dll
   
System.Drawing.Primitives
Return YearsWithSuffix(diplomDate) & vbLF & Format(diplomDate, "dd.MM.yyyy") & " - по текущую дату"
FastReport.Compat.dll
End Function
FastReport.Forms.WPF.dll
FastReport.DataVisualization.dll
Chemsoft.Triteia.ReportClasses.dll
Chemsoft.Triteia.ReportFunctions.Cells.dll
Chemsoft.Triteia.ReportFunctions.Signatures.dll
</syntaxhighlight>
</syntaxhighlight>


===Входные параметры===
Перечень доступных по умолчанию при создании нового отчета сборок может изменяться (чаще - при добавлении нового функционала).
*<code>diplomDate</code> (''Object'') - дата выдачи диплома.


===Выходные данные===
===Добавление сборки===
*<code>String</code>  
Если нужен доступ к другой сборке:
**<code>-</code> - если дата не указана;
*перейти в свойства отчета <code>Отчет|Свойства…</code>;
**многострочный текст, если дата есть; например:
*напротив свойства <code>Скрипт|ReferencedAssemblies|String[] Array</code> нажать на кнопку <code>...</code><br><br>
::{| style="border-collapse: collapse;"
[[Файл: script_prop_1.png | center | border]]
|
 
<syntaxhighlight>
*в открывшемся окне <code>Редактор коллекции строк</code> перейти в конец списка и добавить (с клавиатуры или <code>Вставить</code>) название новой сборки в список сборок отчета:<br><br>
5 лет
[[Файл: net_obj_1.png | center | border]]
15.05.2018 - по текущую дату
 
===Использование сборки===
После добавления в список сборок отчета ссылки на сборку приложения (<code>.exe</code> или <code>.dll</code>) можно обращаться к функции, используя пространство имени (<code>namespace</code>) вашего приложения.
 
===Пример===
Если в приложении определена следующая функция:
 
<syntaxhighlight lang="C#">
namespace Demo
{
  public static class MyFunctions
  {
    public static string Func1()
    {
      return "Hello!";
    }
  }
}
</syntaxhighlight>
</syntaxhighlight>
|}


===Алгоритм===
Обратиться к ней в скрипте можно так:
*проверка на пустоту - является ли входное значение пустым (<code>IsDBNull</code>) или отсутствующим (<code>Nothing</code>); если данных нет, возвращается прочерк;
*расчет лет - вызывается внешняя функция <code>YearsWithSuffix(diplomDate)</code>, которая вычисляет разницу между текущей датой и датой диплома, добавив правильное окончание (<code>год</code> / <code>года</code> / <code>лет</code>);
*форматирование даты - исходная дата преобразуется в стандартный формат <code>дд.мм.гггг.</code>;
*сборка результата - все части склеиваются в одну строку, символ <code>vbLF</code> переносит информацию о датах на новую строку.


==YearsWithSuffix()==
<syntaxhighlight lang="C#">
string hello = Demo.MyFunctions.Func1();
</syntaxhighlight>


Функция <code>YearsWithSuffix()</code> - предназначена для формирования строки, содержащей количество лет и правильное грамматическое окончание существительного «год» (год, года, лет) на основе разницы между переданной датой и текущим моментом.
Если добавить в скрипт директиву <code>using Demo</code>, это позволит укоротить форму обращения к функции:


<syntaxhighlight lang="vb">
<syntaxhighlight lang="C#">
Public Function YearsWithSuffix(inputDate As Date) As String
string hello = MyFunctions.Func1();
Dim yearsDiff As Long = DateDiff(DateInterval.Year, inputDate, Now())
Dim resultDate As Long = yearsDiff
Dim resultString As String = yearsDiff.ToString()
If (resultDate > 20) Then
resultDate = resultDate Mod 10
End If
Select Case resultDate
Case 1
resultString &= $" год"
Case 2 To 4
resultString &= $" года"
Case Else
resultString &= $" лет"
End Select
Return resultString
End Function
</syntaxhighlight>
</syntaxhighlight>


===Входные параметры===
==Обращение к объектам отчета==
*<code>inputDate</code> (''Date'') - дата, от которой ведется отсчет.
 
===Выходные данные===
*<code>String</code> - разница лет до текущего момента с текстом-суффиксом "21 год", "25 лет", "34 года".


===Алгоритм===
Для обращения к объектам отчета (например, объекту <code>Текст</code>) используется имя объекта.  
*вычисляется полное количество лет между <code>inputDate</code> и текущей датой <code>Now()</code> с помощью функции <code>DateDiff</code>;
*<code>resultDate</code> -  техническая переменная для определения логики окончания;
*<code>resultString</code> - строковое представление числа лет;
*обработка исключений (20+ лет) - если число больше 20, применяется операция <code>Mod 10</code> (остаток от деления на 10), чтобы привести числа вроде 21, 22, 25 к виду 1, 2, 5 для подбора окончания;
*<code>Select Case</code> - блок выбора окончания;
*<code>Case 1</code> - если число (или его остаток) равно 1, добавляется слово <code> год</code>;
*<code>Case 2 To 4</code> - если число (или его остаток) в диапазоне от 2 до 4 включительно, добавляется слово <code> года</code>;
*<code>Case Else</code> - в остальных случаях (для 0, 5–19 и специфических остатков) добавляется слово <code> лет</code>;
*возврат итоговой склеенной строки.


==GetNorms()==
===Пример===
Следующий пример вернет высоту объекта <code>Text1</code>:


<syntaxhighlight lang="vb">
<syntaxhighlight lang="C#">
Public Function GetNorms(lowLimit As Double, upLimit As Double) As String
float height = Text1.Height;
If upLimit <> 0 Then
Return "не менее " & lowLimit & vbLF & "не более " & upLimit
End If
If lowLimit <> 0 Then
Return "не менее " & lowLimit
End If
   
Return ""
End Function
</syntaxhighlight>
</syntaxhighlight>


===Входные параметры===
<div style="background-color: #e7f3ff; border-left: 5px solid #2196f3; padding: 15px; margin: 10px 0;">
*<code>lowLimit</code> (''Double'') - нижняя граница нормы;
'''Примечание'''  
*<code>upLimit</code> (''Double'') - верхняя граница нормы.


===Выходные данные===
"Родными" единицами измерения отчета являются экранные пиксели - это необходимо помнить при обращении к таким свойствам объектов, как <code>Left</code>, <code>Top</code>, <code>Width</code>, <code>Height</code>.  
*<code>String</code> текстовое описание диапазона; возвращает пустую строку, если оба параметра равны нулю.


===Алгоритм===
Для перевода пикселей в сантиметры и обратно используются константы, определенные в классе <code>Units</code>:
*проверка верхней границы - если <code>upLimit</code> не равен <code>0</code>, функция возвращает строку с обоими пределами (<code>не менее X, не более Y</code>), разделяя их переносом строки (<code>vbLF</code>);
*проверка нижней границы - если верхний предел равен <code>0</code>, но <code>lowLimit</code> не равен <code>0</code>, возвращается только нижний порог (<code>не менее X</code>);
*значение по умолчанию - если оба параметра равны <code>0</code>, функция возвращает пустую строку.


==NormProcessing()==
<syntaxhighlight lang="C#">
<syntaxhighlight lang="vb">
float heightInPixels = Text1.Height;
Function NormProcessing(ByVal min  As String, ByVal max As String) As String
float heightInCM = heightInPixels / Units.Centimeters;
Dim result As String = ""
Text1.Height = Units.Centimeters * 5; // 5см
Dim hasMin As Boolean = Not String.IsNullOrEmpty(min) AndAlso min <> "0"
Dim hasMax As Boolean = Not String.IsNullOrEmpty(max) AndAlso max <> "0"
If hasMin And hasMax Then
result = min & "-" + max
Else If hasMin Then
result = "≥" & min
Else If hasMax Then
result = "≤" & max
Else
result = "-"
End If
Return result
End Function
</syntaxhighlight>
</syntaxhighlight>
</div>


===Входные параметры===
==[[Объекты Report и Engine]]==
*<code>min</code> (''String'') - строковое значение нижней границы;
*<code>max</code> (''String'') - строковое значение верхней границы.


===Выходные данные===
:[[Объекты Report и Engine#Report|Report]]
*<code>String</code> - форматированная строка диапазона, либо символ прочерка (<code>-</code>).


===Алгоритм===
:*[[Объекты Report и Engine#Список методов|Список методов]]
*проверка наличия данных - определяются два флага (<code>hasMin</code> и <code>hasMax</code>); значение считается валидным, если оно не пустое и не равно строке <code>0</code>;
*выбор формата:
**если есть оба значения - возвращается диапазон через дефис (<code>min-max</code>);
**если есть только <code>min</code> - возвращается значение с символом «больше или равно» (<code>≥min</code>);
**если есть только max - возвращается значение с символом «меньше или равно» (<code>≤max</code>);
*значение по умолчанию - если оба входа пустые или равны <code>0</code>, возвращается дефис (<code>-</code>).


==RemoveTagsSimple()==
:[[Объекты Report и Engine#Engine|Engine]]
<syntaxhighlight lang="vb">
Function RemoveTagsSimple(ByVal input As String) As String
Dim tags() As String = {"<span>", "</span>", "<sub>", "</sub>", "<sup>", "</sup>"}
Dim txt As String = input
   
For Each tag As String In tags
txt = Replace(txt, tag, "", , , CompareMethod.Text)
Next
   
Return txt
End Function
</syntaxhighlight>


===Входные параметры===
:*[[Объекты Report и Engine#Свойства объекта|Свойства объекта]]
*<code>input</code> (''String'') - исходная строка, содержащая HTML-подобные теги.
:*[[Объекты Report и Engine#Формирование страниц готового отчета|Формирование страниц готового отчета]]
:*[[Объекты Report и Engine#Список методов|Список методов]]
:*[[Объекты Report и Engine#Применение методов|Применение методов]]


===Выходные данные===
==Обращение к источнику данных==
*<code>String</code> - очищенный текст без специфических тегов.


===Алгоритм===
Для обращения к самому источнику данных используйте метод <code>GetDataSource</code> объекта <code>Report</code>:
*определение списка - создается массив <code>tags</code>, содержащий конкретные строковые теги - <code><nowiki><span></nowiki></code>, <code><nowiki><sub></nowiki></code>, <code><nowiki><sup></nowiki></code> (открывающие и закрывающие);
*циклическая замена - функция перебирает каждый тег из списка и удаляет его из строки, заменяя на пустую строку;
*игнорирование регистра - используется метод <code>CompareMethod.Text</code>, что позволяет удалять теги независимо от того, написаны они заглавными или строчными буквами (например, удалит и <code><nowiki><span></nowiki></code>, и <code><nowiki><SPAN></nowiki></code>).


==FormatFio()==
<syntaxhighlight lang="C#">
DataSourceBase ds = Report.GetDataSource("Products");
</syntaxhighlight>


<syntaxhighlight lang="vb">
Как правило, класс <code>DataSourceBase</code> используется в скрипте следующим образом:
Function FormatFio(surname As String, name As String, patronymic As String, mode As Integer) As String
Dim f = Trim(surname)
Dim i = Trim(name)
Dim o = Trim(patronymic)
   
Dim i_init = ""
Dim o_init = ""
If Len(i) > 0 Then i_init = Left(i, 1) & "."
If Len(o) > 0 Then o_init = Left(o, 1) & "."
Dim result = ""
Select Case mode
Case 0 ' Фамилия Имя Отчество
result = Trim(f & " " & i & " " & o)
Case 1 ' Фамилия И.О.
result = Trim(f & " " & i_init & o_init)
Case 2 ' И.О. Фамилия
result = Trim(i_init & o_init & " " & f)
End Select


Return GetOrDash(result)
<syntaxhighlight lang="C#">
End Function
// получаем ссылку на источник данных
DataSourceBase ds = Report.GetDataSource("Products");
// инициализируем его
ds.Init();
// перебираем все записи в источнике
while (ds.HasMoreRows)
{
  // получаем значение поля для текущей записи источника
  string productName = (string)Report.GetColumnValue("Products.Name");
  // выполняем с ним какие-то действия...
  // ...
  // переходим на следующую запись
  ds.Next();
}
</syntaxhighlight>
</syntaxhighlight>


===Входные параметры===
==Обращение к данным отчета==
*<code>surname</code> (''String'') - фамилия,
*<code>name</code> (''String'') - имя,
*<code>patronymic</code> (''String'') - отчество;
*<code>mode</code> (''Integer'') - режим форматирования (0, 1 или 2).


===Выходные данные===
*во вкладке кода '''''нельзя использовать квадратные скобки''''' (в отличие от выражений) для обращения к данным отчета - вместо этого используется метод <code>GetColumnValue</code> объекта <code>Report</code>, возвращающий значение поля:
*<code>String</code> - ФИО в выбранном формате; если результат пуст, вызывается внешняя функция <code>GetOrDash</code> (возвращает прочерк).


===Алгоритм===
<syntaxhighlight lang="C#">
*очистка - удаляются лишние пробелы из всех входящих строк (<code>Trim</code>);
string productName = (string)Report.GetColumnValue("Products.Name");
*подготовка инициалов - для имени и отчества берутся первые буквы с точкой (i., o.), если соответствующие строки не пустые;
</syntaxhighlight>
*Выбор формата (по mode):
**<code>0</code> - полное ФИО через пробел (Фамилия Имя Отчество);
**<code>1</code> - фамилия и инициалы слитно (Фамилия И.О.);
**<code>2</code> - инициалы и фамилия через пробел (И.О. Фамилия);
*финальная обработка - результат обрезается от лишних крайних пробелов и передается в <code>GetOrDash</code>.


==CollapseNumbers()==
*имя источника данных и его поля указываются через точку; имя источника может быть составным в случае, если мы обращаемся к источнику данных, используя связь источников данных:
Функция <code>CollapseNumbers()</code> свертывает массив чисел в компактную строку, заменяя последовательные числовые ряды диапазонами.


Она автоматически сортирует входные данные и объединяет три и более идущих подряд числа через дефис (например, 1, 2, 3, 5 преобразуется в 1-3, 5).
<syntaxhighlight lang="C#">
string categoryName = (string)Report.GetColumnValue("Products.Categories.CategoryName");
</syntaxhighlight>


<syntaxhighlight lang="vb">
<div style="background-color: #e7f3ff; border-left: 5px solid #2196f3; padding: 15px; margin: 10px 0;">
Public Function CollapseNumbers(inputNums As Object()) As String
'''Примечание'''
If inputNums Is Nothing OrElse inputNums.Length = 0 Then Return ""


Dim nums(inputNums.Length - 1) As Integer
Для облегчения работы можно использовать окно <code>Данные</code> - из него можно перетаскивать элементы данных в скрипт, при этом дизайнер автоматически создает код для обращения к элементу.
For i As Integer = 0 To inputNums.Length - 1
</div>
nums(i) = CInt(inputNums(i))
Next
Array.Sort(nums)
Dim result As String = ""
Dim index As Integer = 0
While index < nums.Length
Dim startNum As Integer = nums(index)
Dim endNum As Integer = startNum


While index + 1 < nums.Length AndAlso nums(index + 1) = nums(index) + 1
==Обращение к системным переменным==
index += 1
endNum = nums(index)
End While


Dim currentStr As String = ""
Для обращения к системной переменной используйте метод <code>GetVariableValue</code> объекта <code>Report</code>:


If endNum - startNum = 0 Then
<syntaxhighlight lang="C#">
currentStr = startNum.ToString()
DateTime date = (DateTime)Report.GetVariableValue("Date");
ElseIf endNum - startNum = 1 Then
</syntaxhighlight>
currentStr = startNum.ToString() & ", " & endNum.ToString()
Else
currentStr = startNum.ToString() & "-" & endNum.ToString()
End If


If result = "" Then
Список системных переменных можно увидеть в окне <code>Данные</code> - из него можно перетаскивать переменные в скрипт, при этом дизайнер автоматически создает код для обращения к переменной.
result = currentStr
Else
result &= ", " & currentStr
End If


index += 1
==Обращение к итоговым значениям==
End While


Return result
Для обращения к итоговому значению используйте метод <code>GetTotalValue</code> объекта <code>Report</code>:
End Function
 
<syntaxhighlight lang="C#">
float sales = Report.GetTotalValue("TotalSales");
</syntaxhighlight>
</syntaxhighlight>


===Входные параметры===
Список итогов можно увидеть в окне <code>Данные</code> - из него можно перетаскивать итоги в скрипт, при этом дизайнер автоматически создает код для обращения к итогу.
*<code>inputNums</code> (''Object()'') - массив объектов (чисел), которые нужно сгруппировать.


===Выходные данные===
Итоговое значение имеет тип <code>FastReport.Variant</code>. Оно может быть напрямую использовано в любых выражениях, потому что тип <code>FastReport.Variant</code> автоматически приводится к любому типу. Например:
*<code>String</code> - строка с перечисленными числами, где последовательные ряды заменены на диапазоны (например, <code>1, 2, 3, 5</code> превратится в <code>1-3, 5</code>).
 
<syntaxhighlight lang="C#">
float tax = Report.GetTotalValue("TotalSales") * 0.2f;
</syntaxhighlight>


===Алгоритм===
Обращаться к итоговому значению можно в тот момент, когда оно вычислено. Обычно итог "готов к употреблению" в момент печати бэнда, на котором он располагается в отчете.
*подготовка - входные объекты преобразуются в массив целых чисел (Integer) и сортируются по возрастанию;
*поиск последовательностей - цикл проходит по массиву, определяя блоки идущих подряд чисел (где каждое следующее больше предыдущего на 1);
*форматирование группы:
**если число одиночное - записывается просто число;
**если в ряду два числа - записываются через запятую (<code>1, 2</code>);
**если в ряду три и более чисел - записываются через дефис как диапазон (<code>1-3</code>);
*сборка - все обработанные группы объединяются в одну строку через запятую с пробелом.


==AddIndents()==
==Обращение к параметрам отчета==
Добавление абзацев (на перспективу).


<syntaxhighlight lang="vb">
Для обращения к параметру отчета используйте его имя:
Public Function AddIndents(ByVal text As String) As String


    If String.IsNullOrEmpty(text) Then Return ""
<syntaxhighlight lang="C#">
[Parameter1]
</syntaxhighlight>


    Dim indentedText As String = text.Replace(vbCrLf, vbLf & "    ")
Параметры могут быть вложенными. В этом случае указывается имя родительского параметра и через точку имя дочернего параметра:
   
    Return "    " & indentedText


End Function
<syntaxhighlight lang="C#">
[ParentParameter.ChildParameter]
</syntaxhighlight>
</syntaxhighlight>


===Входные параметры===
Параметры, как и поля данных, и системные переменные, имеют определенный тип данных. Он задается в свойстве <code>DataType</code> параметра.  
*<code>text</code> (''String'') - исходный многострочный текст.


===Выходные данные===
От того, какой тип данных имеет параметр, зависит, как его можно использовать в выражении.
*<code>String</code> - текст, в котором каждая строка начинается с отступа (4 пробела).


===Алгоритм===
Дизайнер преобразует обращение к параметру отчета в следующий вид (на примере строкового параметра):
*проверка на пустоту - если входящая строка пустая или <code>Nothing</code>, возвращается пустая строка;
 
*обработка переносов - функция находит все стандартные символы переноса строки (<code>vbLf</code>) и заменяет их на перенос, за которым сразу следуют 4 пробела; это создает отступы для всех строк, кроме первой;
<syntaxhighlight lang="C#">
*обработка первой строки - в начало всей полученной строки принудительно добавляются 4 пробела, чтобы первая строка также имела отступ.
((string)Report.GetParameterValue("Parameter1"))
</syntaxhighlight>

Текущая версия от 04:20, 20 октября 2026

Вкладка Код – содержит программу на языке высокого уровня, которая является частью отчета.

Программа может быть написана на одном из языков .NET:

  • C# (предпочтительно);
  • VisualBasic.NET (нежелательно).

Область применения вкладки Код довольно обширна - она позволяет:

  • выполнить обработку данных, которую невозможно сделать штатными средствами ядра дизайнера;
  • управлять печатью страниц отчета и бэндов на странице;
  • управлять взаимодействием элементов управления на диалоговых формах;
  • управлять формированием динамических объектов Таблица;
  • и многое другое.

Чтобы увидеть код отчета, переключитесь на закладку Код в дизайнере:

Язык для вкладки Код настраивается в меню Отчет|Свойства....

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

Общая информация

Вкладка Код в дизайнере содержит только то, что написано вами.

Во вкладке можно

  • добавить в главный класс кода свои переменные, методы, свойства;
  • создать обработчики событий объектов отчета;
  • добавлять новые классы, если это необходимо (класс может быть добавлен как перед главным классом ReportScript, так и после него.

Во вкладке нельзя

  • удалять, переименовывать или изменять область видимости главного класса ReportScript;
  • переименовывать пространство имен, в котором находится главный класс.

Порядок действий дизайнера при запуске отчета

  • дизайнер добавляет в код список переменных, имена которых совпадают с именами объектов отчета; это делается перед компиляцией кода и позволяет обращаться к объектам отчета по их имени;
  • в код добавляются выражения, имеющиеся в отчете, в виде функций;
  • выполняется компиляция кода, если главный класс не пустой;
  • инициализируются переменные, которые были неявно добавлены в код;
  • обработчики событий, определенные в коде, привязываются к объектам отчета;
  • запускается отчет.

Обработчики событий

Создание обработчика события

  • выделить нужный объект;
  • в окне Свойства нажать кнопку , чтобы переключиться на список событий:
  • выбрать интересующее событие и сделать на нем двойной щелчок мышью - дизайнер добавит в код отчета пустой обработчик события:
private void Text2_BeforePrint(object sender, EventArgs e)
{

}

Удаление обработчика события

  • выбрать событие в окне Свойства;
  • выделить текст имени события и нажамть клавишу Delete:

События

Каждый объект отчета имеет несколько событий, которым можно назначить обработчик – метод из вкладки кода.

Чтобы максимально гибко управлять отчетом, нужно:

  • четко представлять, в какой момент времени вызывается каждое из событий;
  • использовать те события, которые соответствуют поставленной задаче.

Пример

Рассмотрим процесс формирования отчета и события, которые при этом генерируются.

В качестве примера возьмем простой отчет, содержащий одну страницу, один бэнд Данные и два объекта Текст на бэнде:

Порядок событий

  1. В начале отчета вызывается событие StartReport объекта Отчет.
  2. Перед формированием страницы вызывается событие страницы StartPage. Это событие вызывается один раз для каждой страницы шаблона отчета (не путать со страницами готового отчета!). В нашем случае, сколько бы ни было страниц в готовом отчете – событие вызовется один раз, т.к. шаблон отчета состоит из одной страницы.
  3. Затем вызывается событие CreatePage, которое происходит как раз в тот момент, когда страница создается в подготовленном отчете.
  4. Далее начинается печать строк бэнда Данные. Происходит это следующим образом:
    4.1 вызывается событие бэнда BeforePrint;
    4.2 вызываются события BeforePrint всех объектов, лежащих на бэнде;
    4.3 все объекты заполняются данными;
    4.4 вызываются события AfterData всех объектов, лежащих на бэнде;
    4.5 вызывается событие бэнда BeforeLayout;
    4.6 происходит размещение объектов на бэнде (если среди них есть растягиваемые объекты) и подсчет высоты бэнда и его растягивание (если бэнд растягиваемый);
    4.7 вызывается событие бэнда AfterLayout;
    4.8 если бэнд не помещается на свободном месте страницы, формируется новая страница;
    4.9 бэнд и все его объекты выводятся на страницу готового отчета;
    4.10 вызывается событие AfterPrint бэнда;
    4.11 вызывается событие AfterPrint всех объектов бэнда.
  5. Печать строк бэнда происходит до тех пор, пока есть данные в источнике.
  6. После этого формирование отчета в нашем случае завершается и вызываются события FinishPage страницы отчета...
  7. ...и наконец – событие FinishReport объекта Отчет.

Выводы

  • используя события разных объектов, можно контролировать практически каждый момент формирования отчета;
  • большинство действий можно выполнить, используя только событие бэнда BeforePrint – любые изменения, внесенные в объект, будут тут же отображены;
  • в событии BeforePrint невозможно анализировать, на какой странице будет напечатан бэнд, если он растягиваемый – ведь подсчет высоты бэнда будет выполнен в пункте 4.6;
  • определить номер страницы для растягиваемого бэнда можно с помощью следующих событий
  • AfterLayout в пункте 4.7;
  • AfterPrint в пункте 4.10 (правда, в этом случае бэнд уже будет напечатан и действия над объектами ничего не дадут).

Обращение к объектам .NET

Сборки по умолчанию

Из вкладки кода можно обращаться к любым объектам .NET, которые определены в сборках, подключаемых к новому отчету по умолчанию.

На момент создания описания к ним относятся:

System.dll
System.Xml.dll
System.Data.dll
System.Drawing.dll
System.Drawing.Primitives
FastReport.Compat.dll
FastReport.Forms.WPF.dll
FastReport.DataVisualization.dll
Chemsoft.Triteia.ReportClasses.dll
Chemsoft.Triteia.ReportFunctions.Cells.dll
Chemsoft.Triteia.ReportFunctions.Signatures.dll

Перечень доступных по умолчанию при создании нового отчета сборок может изменяться (чаще - при добавлении нового функционала).

Добавление сборки

Если нужен доступ к другой сборке:

  • перейти в свойства отчета Отчет|Свойства…;
  • напротив свойства Скрипт|ReferencedAssemblies|String[] Array нажать на кнопку ...

  • в открывшемся окне Редактор коллекции строк перейти в конец списка и добавить (с клавиатуры или Вставить) название новой сборки в список сборок отчета:

Использование сборки

После добавления в список сборок отчета ссылки на сборку приложения (.exe или .dll) можно обращаться к функции, используя пространство имени (namespace) вашего приложения.

Пример

Если в приложении определена следующая функция:

namespace Demo
{
  public static class MyFunctions
  {
    public static string Func1()
    {
      return "Hello!";
    }
  }
}

Обратиться к ней в скрипте можно так:

string hello = Demo.MyFunctions.Func1();

Если добавить в скрипт директиву using Demo, это позволит укоротить форму обращения к функции:

string hello = MyFunctions.Func1();

Обращение к объектам отчета

Для обращения к объектам отчета (например, объекту Текст) используется имя объекта.

Пример

Следующий пример вернет высоту объекта Text1:

float height = Text1.Height;

Примечание

"Родными" единицами измерения отчета являются экранные пиксели - это необходимо помнить при обращении к таким свойствам объектов, как Left, Top, Width, Height.

Для перевода пикселей в сантиметры и обратно используются константы, определенные в классе Units:

float heightInPixels = Text1.Height;
float heightInCM = heightInPixels / Units.Centimeters;
Text1.Height = Units.Centimeters * 5; // 5см
Report
Engine

Обращение к источнику данных

Для обращения к самому источнику данных используйте метод GetDataSource объекта Report:

DataSourceBase ds = Report.GetDataSource("Products");

Как правило, класс DataSourceBase используется в скрипте следующим образом:

// получаем ссылку на источник данных
DataSourceBase ds = Report.GetDataSource("Products");
// инициализируем его
ds.Init();
// перебираем все записи в источнике
while (ds.HasMoreRows)
{
  // получаем значение поля для текущей записи источника
  string productName = (string)Report.GetColumnValue("Products.Name");
  // выполняем с ним какие-то действия...
  // ...
  // переходим на следующую запись
  ds.Next();
}

Обращение к данным отчета

  • во вкладке кода нельзя использовать квадратные скобки (в отличие от выражений) для обращения к данным отчета - вместо этого используется метод GetColumnValue объекта Report, возвращающий значение поля:
string productName = (string)Report.GetColumnValue("Products.Name");
  • имя источника данных и его поля указываются через точку; имя источника может быть составным в случае, если мы обращаемся к источнику данных, используя связь источников данных:
string categoryName = (string)Report.GetColumnValue("Products.Categories.CategoryName");

Примечание

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

Обращение к системным переменным

Для обращения к системной переменной используйте метод GetVariableValue объекта Report:

DateTime date = (DateTime)Report.GetVariableValue("Date");

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

Обращение к итоговым значениям

Для обращения к итоговому значению используйте метод GetTotalValue объекта Report:

float sales = Report.GetTotalValue("TotalSales");

Список итогов можно увидеть в окне Данные - из него можно перетаскивать итоги в скрипт, при этом дизайнер автоматически создает код для обращения к итогу.

Итоговое значение имеет тип FastReport.Variant. Оно может быть напрямую использовано в любых выражениях, потому что тип FastReport.Variant автоматически приводится к любому типу. Например:

float tax = Report.GetTotalValue("TotalSales") * 0.2f;

Обращаться к итоговому значению можно в тот момент, когда оно вычислено. Обычно итог "готов к употреблению" в момент печати бэнда, на котором он располагается в отчете.

Обращение к параметрам отчета

Для обращения к параметру отчета используйте его имя:

[Parameter1]

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

[ParentParameter.ChildParameter]

Параметры, как и поля данных, и системные переменные, имеют определенный тип данных. Он задается в свойстве DataType параметра.

От того, какой тип данных имеет параметр, зависит, как его можно использовать в выражении.

Дизайнер преобразует обращение к параметру отчета в следующий вид (на примере строкового параметра):

((string)Report.GetParameterValue("Parameter1"))