Advanced programming


You can create reports with the report  designer (iPlus control element " gip.core.layoutengine. VBReportEditor "). Like UI designs, reports are programmed in XAML and saved as flow documents . First, familiarize yourself with documents in WPF on the Microsoft documentation page before reading any further.

The classes or elements  from the ".NET framework" that are required to create a flow document have been expanded to include the following features in the iPlus framework:

  • Data binding,
  • Iteration of data collections,
  • Headers and footers,
  • Integration of resources (e.g. images ...)
  • Formatting of data

These iPlus report elements can only be used in combination with the class " gip.core.reporthandler.Flowdoc. ReportPaginator " which is an extension of  DocumentPaginator class. The ReportPaginator in turn is integrated in the " gip.core.reporthandler.Flowdoc. ReportDocumentclass, to generate a printable XpsDocument . The generated XPS documents can


Reports are essentially designs that are populated with data and then put on paper or in a legible format. The data context of a report is primarily a business object or, alternatively its storable query . For this reason reports can be managed and added for each business object (symbol  in the ribbon).

 

VBBSOReport

The design is then edited with the business object gip.core.reporthandler. VBBSOReport ( report designer ). VBBSOReport is instantiated just-in-time as a child instance of the opened business object.

A VBBSOReport child instance is also used for the print preview (symbol ) and for printing.

The printing process does not necessarily need a surface, but can also be triggered in the background (e.g. on the server). Read more about this in the section "Printing in the Background" with VBBSOReport

 

Designer

The designer is divided into four tabs: 

 

The graphic designer only supports you with formatting. The structure and the link to data content must currently be edited in the XAML tab:

 

 

Before we go into the structure and the most important XAML sections in a report, an overview of the inheritance hierarchy of the iPlus report elements:

 

The light blue classes are elements from the ".NET Framework ". The yellow classes are iPlus report items. Use iPlus report elements in the XAML code so that you can insert data from business objects or other data models into a flow document.

 

The outermost element is a FlocDocument . Here you set the paper size with the PageHeight and PageWidth properties . The information is given in pixels, with a point density of 96 PPI (pixels per inch). In the following example code, a report for A4 was defined:

 

xmlns:vbr="http://www.iplus-variobatch.com/ACFramework/report/xaml" Include the namespace so that you can use iPlus report elements.

Within the flow document, section elements are used to divide a page into groups. Section elements are comparable to div elements from html . However, if you use the iPlus sections in the report,

  • SectionReportHeader (optional),
  • SectionReportFooter (optional) and
  • SectionDataGroup (minimum one occurrence).

 

Headers and footers

Use the < SectionReportHeader>  and <SectionReportFooter> elements so that a header and footer area is printed on every print page if the data content becomes so long that page breaks have to take place. Use the PageHeaderHeight and PageFooterHeight properties to specify a percentage of how much space the headers and footers should take up in relation to the total page . Make sure that you do not make the content of the header and footer larger than the fixed reserved area in percent. Otherwise the content will be cut off! The page header can be skipped on the report first page, to achive this you can set property ShowHeaderOnFirstPage="False".

 

Content

The remaining content between the optional header and footer elements should be declared with the  < SectionDataGroup> elements  .

Important: Please do not use any other block elements between these three section types, such as paragraphs or tables,  because otherwise the calculation of the page breaks by the ReportPaginator would not be correct. All other report elements must always be within these three section types!


Paragraph is the most common element used to display continuous text. For data-based reports, however, the exact positioning of a data field is most important. You can do this with  Table elements. More on this at https://docs.microsoft.com/en-us/dotnet/framework/wpf/advanced/table-overview .

The following basic structure always applies to tables:

<Table>
  <Table.Columns>
    <TableColumn>
  <TableRowGroup>
    <TableRow>
      <TableCell>
        <Paragraph>

Here's an example:

 

Use two <TableRowGroup> elements within a table to describe column headings with the first element and output the data with the second.

 

Before we go to the elements responsible for outputting data in a flow document, you must first understand where the ReportPaginator (report generator) finds its data. When printing, the ReportPaginator is given an instance of the ReportData class, which contains the report data to be printed and is stored in the ReportDocumentValues ​​dictionary:

public class ReportData
{
public Dictionary<string, object> ReportDocumentValues {get; set;}
}

Business objects which need to be printed are first cloned and then entered as a reference in ReportDocumentValues. The key is the class name (ACIdentifier) where the printing report (ACClassDesign) belongs. The reason why a clone is used for printing is that the ReportPaginator runs through lists and changes the Selected properties. If ReportPaginator runs on the original business object, the data on the user interface would change during the loop runs and this is a side effect that must be prevented.

ReportDocumentValues ​​can contain an ACQueryDefintion instance instead of a business object clone. Then the key is the ChildACUrl of the ACQueryDefinition instance.

ReportDocumentValues ​​can also contain other data objects which, however, have to be explicitly added through individual programming.

 


In order to output the data that is stored in ReportData, elements are required that are derived from " gip.core.reporthandler.Flowdoc. InlinePropertyValueBase " . InlinePropertyValueBase has two important properties:

  • string VBContent : You already got to know this property in the previous chapter " GUI Design IVBContent ". It is used to address properties relative to the data context. The data context is the first element in ReportDocumentValues. This is either the business object to be printeditself or an ACQueryDefinition instance. If another data object from ReportDocumentValues ​​is to be used as the data context, the DictKey property must be set explicitly:
  • string DictKey : Name of the key in ReportDocumentValues ​​to use a different data object.

The following print elements are derived from InlinePropertyValueBase:

  • InlineDocumentValue : For printing a data field. (See the table sample XAML code above).
  • InlineContextValue : For printing predefined macros (enum ReportContextValueType). Set DictKey with one of these predefined constants: PageNumber, PageCount, ReportName, ReportTitle, PrintingDate
  • InlineACMethodValue : For printing a parameter from a virtual method
  • InlineTableCellValue : For printing a data field in the data line. Rows of data are generated by iterating TableRowData elements.
  • InlineFlowDocContentValue: For printing a formated text from the Flow document XAML. The parent container for this element can be the Paragraph or a TableCell.

 


In order to display data collections on the surface, you need iPlus ItemsControls, which implement the IVBSource interface. IVBSource has the property VBSource to address a data collection that has been identified with the attribute class ACPropertyList. Exactly the same principle is implemented in the abstract class " gip.core.reporthandler.Flowdoc. TableRowDataBase " so that data collections can be printed. TableRowDataBase therefore has the properties " string VBSource " and " string DictKey". As with ItemsControls, the data context changes with the bound data source. For all print elements (child elements) that are within a TableRowDataBase, the VBContent is specified relative to the data context.

TableRowDataBase is derived from TableRow and behaves like a kind of template. During the iteration of the bound data collection, the template is cloned for each data object and each cell is  filled with data that are addressed using InlineTableCellValue The new table row filled with data is then added to the rows list of the parent TableRowGroup . Finally, the TableRowDataBase template is removed from the rows list.

There are the following print elements that are derived from TableRowDataBase:

  • TableRowData : For printing cells that have to be specified explicitly with InlineTableCellValue.
  • TableRowDataDyn : Cells are generated dynamically for each public property of an object that is in the data collection.
    • If the object is an IACObject that is registered in the iPlus runtime, all properties that were published with the ACClassPropertyInfo attribute class are output .
    • If the data collection is an ACQueryDefinition , the properties that are declared in ACColumns are printed out .
    • For unknown classes, the type is analyzed by reflection and all public properties are output.
    • If the data collection is a DataTable , then all DataColumns are output.
  • TableRowDataDynHeader : Use to generate this class dynamically by column headings when you  TableRowDataDyn use .

 

Examples

To put order items from the IVBSource example on paper, the XAML code would look like this:

 

To output all fields of the table InOrderPos published in the partial class with ACPropertyEntity, you can use TableRowDataDyn:

 


With BlockUIContainer you can render interface elements derived from UIElement on paper. Therefore it can also be used to print images. In the chapter "Use of resources" you got to know the MarkupExtension VBStaticResource with which you can load bitmaps from the database. You can also use VBStaticResource in flow documents as you can see in the following example:

 <BlockUIContainer>
  <vb:VBBorder Width="80" Height="50" HorizontalAlignment="Left">
    <Image Tag="vb:VBStaticResource ResourceKey=ACProject(Root)\\ACClass(Root)\\ACClass(Environment)\\ACClassDesign(iPlusLogoPNG)" Source="{vb:VBStaticResource ResourceKey=ACProject(Root)\\ACClass(Root)\\ACClass(Environment)\\ACClassDesign(iPlusLogoPNG)}" />
  </vb:VBBorder>
</BlockUIContainer>

 


You can print barcodes with the InlineBarcode element:

<TableCell>
<Paragraph TextAlignment="Center">
<vbr:InlineBarcode BarcodeType="QRCODE" QRPixelsPerModule="20"
VBContent="CurrentFacilityCharge.FacilityChargeID" />
</Paragraph>
<Paragraph TextAlignment="Center">
<vbr:InlineBarcode BarcodeType="CODE128" BarcodeWidth="800" BarcodeHeight="100"
VBContent="CurrentFacilityCharge.FacilityChargeID" />
</Paragraph>
</TableCell>

The "BarcodeType" property allows the following values:

public enum BarcodeType
{
UNSPECIFIED = 0,
UPCA = 1,
UPCE = 2,
UPC_SUPPLEMENTAL_2DIGIT = 3,
UPC_SUPPLEMENTAL_5DIGIT = 4,
EAN13 = 5,
EAN8 = 6,
Interleaved2of5 = 7,
Interleaved2of5_Mod10 = 8,
Standard2of5 = 9,
Standard2of5_Mod10 = 10,
Industrial2of5 = 11,
Industrial2of5_Mod10 = 12,
CODE39 = 13,
CODE39Extended = 14,
CODE39_Mod43 = 15,
Codabar = 16,
PostNet = 17,
BOOKLAND = 18,
ISBN = 19,
JAN13 = 20,
MSI_Mod10 = 21,
MSI_2Mod10 = 22,
MSI_Mod11 = 23,
MSI_Mod11_Mod10 = 24,
Modified_Plessey = 25,
CODE11 = 26,
USD8 = 27,
UCC12 = 28,
UCC13 = 29,
LOGMARS = 30,
CODE128 = 31,
CODE128A = 32,
CODE128B = 33,
CODE128C = 34,
ITF14 = 35,
CODE93 = 36,
TELEPEN = 37,
FIM = 38,
PHARMACODE = 39,
QRCODE = 99
}

For QR barcodes (2D) , the QRPixelsPerModule property  must be set, with which you define how large a module is in pixels (box). 

For simple barcodes (1D) , the properties  BarcodeWidth and  BarcodeHeight (pixel) must be set, with which you define how big the bitmap should be that should be generated.


Checkbox

For Boolean values, you can use InlineBoolValue:

<TableCell>
<Paragraph>
<vbr:InlineBoolValue VBContent="CurrentMaterial\UsageACProgram" />
</Paragraph>
</TableCell>

 

Aggregate functions

With aggregate functions , you can aggregate field values ​​that you have output with  InlinePropertyValueBase elements (which implement the IAggregateValue interface) and have the result output at another point.

All you have to do is provide  the " AggregateGroup " property with a unique key in the InlinePropertyValueBase element . You then specify the print element InlineAggregateValue somewhere else and reference this key so that the aggregated value can be output.

Take a look at the following example:

 

At the end, five different aggregation functions are called and the calculation result is output.

All refer to "QuantityGroup", which was defined in InlineTableCellValue and refers to the "TargetQuantity" property. During the iteration of the InOrderPosList, the values ​​of the InOrderPos.TargetQuantity property are saved under the QuantityGroup key.

  • With the first InlineAggregateValue, a sum function " Sum " was declared with the property " AggregateValueType " . This means that the previously saved "TargetQuantity" values ​​should be added up.
  • With " Average " the average of all "TargetQuantity" is calculated and output.
  • With " Count ", the number of all order items (or loop runs).
  • With " Maximum " the largest "TargetQuantity" value.
  • Mit "Minimum" der kleinste "TargetQuantity"-Wert.