Architecture
A schematic diagram of Genero Report Writer for C#
Scalability
A schematic diagram illustrating the distributed nature of Genero Report Writer for C#
Detailed feature overview
Customizing the presentation
Data production and presentation separated
Structured data source
Performance & scalability
Sophisticated layout engine
APIs
Report viewers and devices
Run time localization
Templates
Maintenance
Data source generation
Database support
All of the industry’s leading databases are supported:
Code data model as composition of plain objects
In this example we use a plain C# object that is annotated for XML serialization as shown in the source below:
//The XmlRoot annotation causes a global element declaration to be produced in the schema. [Serializable] [XmlRoot] public class Sales { //The XmlElement annotation maps a property to an XML element. //The Genero Engine does not support optional variables so setting "IsNullable = true" is mandatory. //If a variable needs to be optional then set the variable to null whenthere is no value. //If a primitive type needs to be optional then use the c# nullable type //instead (e.g "int?" for "int"). [XmlElementAttribute(IsNullable = true)] public String shopName; public int zipCode; public DateTime day;
Generate schema with xsd.exe
Graphical reports are designed based on a XML schema that matches the data to be serialized.
The command line tool “xsd.exe” can be used to generate the schema:
xsd.exe Sales.exe
The schema for the sample program reads as follows:
<?xml version="1.0" encoding="utf-8"?> <xs:schema elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:element name="Sales" nillable="true" type="Sales" ></xs:element> <xs:complexType name="Sales"> <xs:sequence> <xs:element minOccurs="1" maxOccurs="1" name="shopName" nillable="true" type="xs:string" ></xs:element> <xs:element minOccurs="1" maxOccurs="1" name="zipCode" type="xs:int" ></xs:element> <xs:element minOccurs="1" maxOccurs="1" name="nillable" nillable="true" type="xs:int" ></xs:element> <xs:element minOccurs="1" maxOccurs="1" name="day" type="xs:dateTime" ></xs:element> <xs:element minOccurs="0" maxOccurs="unbounded" name="items" nillable="true" type="SalesItem" ></xs:element> </xs:sequence> </xs:complexType> <xs:complexType name="SalesItem"> <xs:sequence> <xs:element minOccurs="1" maxOccurs="1" name="articleName" nillable="true" type="xs:string" ></xs:element> <xs:element minOccurs="1" maxOccurs="1" name="category" type="Category" ></xs:element> <xs:element minOccurs="1" maxOccurs="1" name="price" type="xs:double" ></xs:element> <xs:element minOccurs="1" maxOccurs="1" name="runningTotal" type="xs:double" ></xs:element> </xs:sequence> </xs:complexType> <xs:simpleType name="Category"> <xs:restriction base="xs:string"> <xs:enumeration value="Furniture" ></xs:enumeration> <xs:enumeration value="Art" ></xs:enumeration> <xs:enumeration value="Supplies" ></xs:enumeration> <xs:enumeration value="Travelling" ></xs:enumeration> </xs:restriction> </xs:simpleType> <xs:element name="SalesItem" nillable="true" type="SalesItem" ></xs:element> </xs:schema>
Run report
Select report design
if (args.length == 0) { designFile = "SalesList.4rp"; } else { designFile = args[0]; }
Configure the output
Select PDF output
PDFRenderer renderer = new PDFRenderer(handler);
Serialize model
Use the .Net serializer to serialize the data.
report.runFromSerializable(data);
Find below the complete listing of the C# program:
using gre; using System; using System.Collections.Generic; using System.Xml.Serialization; namespace Sales { //The XmlRoot annotation causes an global element declaration to be produced in the schema. [Serializable] [XmlRoot] public class Sales { //The XmlElement annotation maps a property to an XML element. //The Genero Engine does not support optional variables so setting "IsNullable = true" is mandatory. //If a variable needs to be optional then set the variable to null whenthere is no value. //If a primitive type needs to be optional then use the c# nullable type //instead (e.g "int?" for "int"). [XmlElementAttribute(IsNullable = true)] public String shopName; public int zipCode; public DateTime day; //This and any other public collection will be serialized in the order they are declared descending //recursively into the classes contained in the collections. [XmlElementAttribute(IsNullable = true)] public Listitems = new List (); public Sales(String shopName, int zipCode, DateTime day) { this.shopName = shopName; this.zipCode = zipCode; this.day = day; int i = 0; items.Add(new SalesItem("Tablelamp", SalesItem.Category.Furniture, 23.00, null)); items.Add(new SalesItem("Tablelamp", SalesItem.Category.Furniture, 267.00, items[i++])); items.Add(new SalesItem("Officechair", SalesItem.Category.Furniture, 155.00, items[i++])); items.Add(new SalesItem("Grandfather clock", SalesItem.Category.Furniture, 329.00, items[i++])); items.Add(new SalesItem("Scissors", SalesItem.Category.Supplies, 19.00, items[i++])); items.Add(new SalesItem("Measuring tape", SalesItem.Category.Supplies, 23.00, items[i++])); items.Add(new SalesItem("Sunglasses", SalesItem.Category.Travelling, 15.95, items[i++])); items.Add(new SalesItem("Penknife", SalesItem.Category.Travelling, 6.25, items[i++])); items.Add(new SalesItem("Ornateangel", SalesItem.Category.Art, 1.95, items[i++])); } /** Default Constructor that is required for deserialization. In this program this is never used. */ public Sales() { } /** Runs the report using the design file specified in args[0] or "SalesList.4rp" otherwise. The program creates the file "SalesList.pdf" and opens it using System.Diagnostics.Process.Start which will typically invoke the Acrobat Reader. */ static void Main(string[] args) { String designFile; String outputFilename = "SalesList.pdf"; if (args.Length == 0) { designFile = "SalesList.4rp"; } else { designFile = args[0]; } FormatHandler handler = new FormatWriter(outputFilename); PDFRenderer renderer = new PDFRenderer(handler); FourRpLayouter report = new FourRpLayouter(designFile, renderer); report.debugLevel = 9; Sales data = new Sales("Columbus Arts", 75038, new DateTime()); report.runFromSerializable(data); // open the file System.Diagnostics.Process.Start(outputFilename); } } public class SalesItem { public enum Category { Furniture, Art, Supplies, Travelling }; [XmlElementAttribute(IsNullable = true)] public String articleName; public Category category; public double price; public double runningTotal; //The previous item is passed to allow computing the running total. public SalesItem(String articleName, Category category, double price, SalesItem previousItem) { this.articleName = articleName; this.category = category; this.price = price; this.runningTotal = previousItem == null ? price : previousItem.runningTotal + price; } /** Default Constructor that is required for deserialization. In this program this is never used. */ public SalesItem() { } } }