[]
        
(Showing Draft Content)

Data Binding

A PrintDocument may be data bound to populate the control with data by fetching it from an underlying data source. The main property that facilitates data binding is the DataBinding property in RenderObject, of the type C1DataBinding, which allows to specify the data source for data shown by the render object.

The document can contain the database schema (represented by the class C1DataSchema, and include the data base connection info, SQL queries etc.) inside. The C1DataBinding objects within the document can reference properties of that schema. If all data-bound objects in a document reference only the properties of the C1DataSchema of the document itself, the document becomes "data re-flowable". That is, the document can be regenerated independently of the program used to create it, with data completely updated from the database. Also, the C1DataBinding object may reference existing data sources (DataTable and so on) which were created on the form or elsewhere in the program that created that PrintDocument.

Data Binding in Render Objects

When a render object is created, the data binding for it is not created initially. It is created when the DataBinding property is referenced in the user code. This is depicted in the code snippet below:

RenderText rt = new RenderText();
// ...
if (rt.DataBinding != null)
{
MessageBox.Show("Data binding defined.");
}

The condition in the previous code will always evaluate to True. Thus, if you only want to check whether data binding exists on a particular render object, you should use the DataBindingDefined property instead:

RenderText rt = new RenderText();
// ...
if (rt.DataBindingDefined)
{
MessageBox.Show("Data binding defined."); }

This is similar to the Handle and IsHandleCreated properties of the WinForms Control class.

During document generation, the RenderObjectsList collection is created. In such a case, three different situations are possible:

  • The Copies property on the render object is null. This means that the object is not data bound, and is processed as usual. The Fragments property of the object can be used to access the actual rendered fragments of the object on the generated pages.
  • The Copies property on the render object is not null, but Copies.Count is 0. This means that the object is data bound, but the data set is empty (contains no records). In such situations the object is not show in the document at all, that is, no fragments are generated for the object. For an example see Binding to the Empty List in the DataBinding sample.
  • The Copies property on the render object is not null and Copies.Count is greater than 0. This means that the object is data bound, and the data source is not empty (contains records). During the document generation, several copies of the render object will be created and placed in this collection. Those copies will then be processed and fragments will be generated for each copy as usual.

Working with Data-Bound Tables

A RenderTable is used to represent a data table in PrintDocument. It can be data bound using the DataBinding property in the TableVectorGroup, which is the base class for table row and column groups.

Data-bound tables in PrintDocument application.

Please note that it is not just groups of rows, but also groups of columns that can be bound to data. That is, a table can grow not only downwards, but also sideways. The group hierarchy in data-bound tables is based on the hierarchy of the TableVectorGroup objects, and this is depicted in the code below:

//define render table
RenderTable rt = new RenderTable();
rt.Style.GridLines.All = LineDef.Default;
// define data schema
DataSource ds = CreateDemoDataSource();
DataSet dsCities = new DataSet(ds, "SELECT Customer_demo.Company, [Order].* FROM (Customer_demo INNER JOIN[Order] ON Customer_demo.ID = [Order].CustomerID) ORDER BY Customer_demo.Company, [Order].PaymentType");
doc.DataSchema.DataSources.Add(ds);
doc.DataSchema.DataSets.Add(dsCities);
// define data-binding within render table
TableVectorGroup g = rt.RowGroups[0, 6];
g.DataBinding.DataSource = dsCities;
g.DataBinding.Grouping.Expressions.Add("Fields!Company.Value");
// add aggregates
doc.DataSchema.Aggregates.Add(new Aggregate("CompanySum", "Fields!PaymentAmount.Value", g.DataBinding, RunningEnum.Group, AggregateFuncEnum.Sum));
doc.DataSchema.Aggregates.Add(new Aggregate("Sum", "Fields!PaymentAmount.Value", g.DataBinding, RunningEnum.Document, AggregateFuncEnum.Sum));
g = rt.RowGroups[1, 4];
g.DataBinding.DataSource = dsCities;
g.DataBinding.Grouping.Expressions.Add("Fields!PaymentType.Value");
doc.DataSchema.Aggregates.Add(new Aggregate("PaymentTypeCount", "Fields!PaymentAmount.Value", g.DataBinding, RunningEnum.Group, AggregateFuncEnum.Count));
doc.DataSchema.Aggregates.Add(new Aggregate("PaymentTypeSum", "Fields!PaymentAmount.Value", g.DataBinding, RunningEnum.Group, AggregateFuncEnum.Sum));
doc.DataSchema.Aggregates.Add(new Aggregate("PaymentTypeQuantity", "Fields!Quantity.Value", g.DataBinding, RunningEnum.Group, AggregateFuncEnum.Sum));
g = rt.RowGroups[3, 1];
g.DataBinding.DataSource = dsCities;
// create aggregates
doc.Body.Children.Add(rt);
doc.Generate();

As you can observe from the code, the C1DataBinding class provides the Grouping property to get the C1.C1Preview.DataBinding.Grouping object that determines how data retrieved by the current data binding is grouped. The Grouping class provides a set of expressions that determine the grouping of data in a data-bound object in a PrintDocument. It is the Expressions property in the Grouping class that gets the collection of expressions defining data grouping. When the document is generated, a new group starts if at least one expression in this collection evaluates to a different value. The C1DataSchema class provides the Aggregates property to get the collection of named Aggregate objects defined in the current data schema.

The Aggregate(string name, string expressionText, C1.C1Preview.DataBinding.C1DataBinding dataBinding, C1.C1Preview.DataBinding.RunningEnum running, C1.C1Preview.DataBinding.AggregateFuncEnum func) method overload in the Aggregates class initializes a new instance of the class and assigns the name, expression, data binding, scope and function of the aggregate.

The overload method passes the following parameters:

  • name: A string assigned to the Name property of the aggregate.
  • expressionText: A string assigned to the ExpressionText property of the aggregate.
  • dataBinding: Assigned to the DataBinding property of the aggregate.
  • running: A value assigned to the Running property of the aggregate.
  • func: A value assigned to the Func property of this aggregate.