Advanced programming


As you learned from the previous chapter , an ACComponent or usually rather a business object is cloned before it is printed. When cloning, the same database queries are executed as on the original instance and all properties are copied that are known to the iPlus runtime using the ACProperty attribute classes .

You must explicitly set other unknown properties or other unknown data filters that are required for the print report during the cloning process. The following code is taken from the BSOInOrder class from the sample project :

public override object Clone()
{
BSOInOrder clone = base.Clone() as BSOInOrder;
if (clone != null)
clone.PrintPropExample = this.PrintPropExample;
return clone;
}

The local property "PrintPropExample" is copied here during the cloning process.


After the cloning process, the printing process is started (to be more precise: filling out the Flowdocument template with data). So that you still have intervention options before and after the printing process, you can use the virtual method OnPrintingPhase defined in the class ACComponent, overwrite :

public override void OnPrintingPhase(object reportEngine, ACPrintingPhase printingPhase)
{
base.OnPrintingPhase(reportEngine, printingPhase);
if (printingPhase == ACPrintingPhase.Started) { ... }
else if (printingPhase == ACPrintingPhase.Cancelled) { ... }
else if (printingPhase == ACPrintingPhase.Completed) { ... }
}

This virtual method is called twice:

  1. ACPrintingPhase .Started : Before the ReportPaginator class becomes active and generates the report data, you can add further print data to the ReportData instance here (see next section).
  2. ACPrintingPhase .Completed or  ACPrintingPhase .Cancelled : After a successful or aborted printing process (eg in the case of an unhandled exception), final work can be programmed here. This phase is usually required to unsubscribe from printing events (see the next but one section)

Within the "Started" printing phase, you can add further print data that you reference in the iPlus print elements using DictKey .

First, take a look at the following sample code:

ReportDocument currentPrintingDoc = reportEngine as ReportDocument;
ReportData reportData = (currentPrintingDoc.ReportData as IList<ReportData>).FirstOrDefault();
if (reportData != null && reportData.ACClassDesign != null)
{
if (reportData.ACClassDesign.ACIdentifier == "TableRowDataDyn")
{
DataTable dataTable = CreateOrderTable();
InsertOrders(dataTable);
if (reportData.ReportDocumentValues.ContainsKey("DataTableOrder"))
reportData.ReportDocumentValues.Remove("DataTableOrder");
reportData.ReportDocumentValues.Add("DataTableOrder", dataTable);
}
}

You can cast the reportEngine variable transferred in OnPrintingPhase in " gip.core.reporthandler.Flowdoc. ReportDocument" .

(If you have created a report with ListAndLabel ( design categories with prefix "DULL ..." ,) cast reportEngine to gip.core.reporthandler.VBListLabel (derived from ListLabel ).

You can get ReportData by accessing the first element in the "ReportDocument.ReportData" list. You can find out which report is to be printed by accessing the ACClassDesign property. The sample project contains two sample reports "TableRowData" and "TableRowDataDyn" .

The report with the ACIdentifier "TableRowDataDyn" contains the following line which wants to access an object in ReportData that is stored under the key " DataTableOrder ":

<vbr:TableRowDataDyn DictKey="DataTableOrder" ColumnWidthInfos="300;" />

This object is a DataTable which is added to the dictionary under the key " DataTableOrder " via " ReportDocumentValues.Add () " .

In ReportDocumentValues  you can add any number of simple or complex objects. If the objects are known to the iPlus runtime via ACClassInfo and ACClassPropertyInfo , you can define the path to the property in VBContent as ACUrl . For unknown classes , please use the classic dot notation for property paths


You can influence every iPlus print element that is processed by the ReportPaginator during the printing process by subscribing to a suitable print event:

currentPrintingDoc.NextRow += OnPrinting_NextRow;
currentPrintingDoc.NewCell += OnPrinting_NewCell;
currentPrintingDoc.SetFlowDocObjValue += OnPrinting_SetFlowDocObjValue;

In addition to these three events, there are four more. With  ImageProcessingImageProcessed and  ImageError you can control the printing process of images and with GetPageCompleted you are notified when a page break has occurred.

Do not forget to unsubscribe events the second time the OnPrintingPhase method is called (Phase Completed or Canceled)!

 

SetFlowDocObjValue event

This event is triggered when a simple print element has been filled with data. In the following example, we want to highlight the number in the "TargetQuantity" field:

void OnPrinting_SetFlowDocObjValue(object sender, PaginatorOnSetValueEventArgs e)
{
ReportDocument currentPrintingDoc = sender as ReportDocument;
if (currentPrintingDoc != null && e.FlowDocObj.VBContent == "TargetQuantity")
{
TextElement element = e.FlowDocObj as TextElement;
if (element != null)
element.FontWeight = FontWeights.Bold;
}
}

 

NextRow event

NextRow is triggered when a new table row has been cloned during the iteration of a data collection.

void OnPrinting_NextRow(object sender, PaginatorNextRowEventArgs e)
{
}

 

NewCell event

NewCell is triggered when a table cell of  a cloned table row is filled with data. In the following example, special formatting is to be carried out for the one value from the "TargetQuantity" column:

void OnPrinting_NewCell(object sender, PaginatorNewTableCellEventArgs e)
{
if (e.FieldName == "TargetQuantity" && e.FieldValue != null && e.FieldValue is double)
{
double value = (double)e.FieldValue;
if (value > 0.0001)
{
string valueAsString = InlineValueBase.FormatValue(value, "0.0000",
(e.TableRow as TableRowDataBase).CultureInfo,
(e.TableRow as TableRowDataBase).MaxLength);
((e.NewCell.Blocks.FirstBlock as Paragraph).Inlines.FirstInline as Run).Text
= valueAsString;
}
}
}

 


Here again all topics from the above sections summarized:

 


Reports can not only be printed by the user via the interface, but can also be done on the server in the background. 

There are two options here:

  1. If you would like to print during a workflow , please use the workflow class  gip.core.autocomponent. PWNodePrint. In the configuration you can then specify which business object and which report should be printed.
  2. You trigger the printing process programmatically. For this purpose, the following code example from the ACComponent base class, with which the current status of an instance is printed out:

 

Basically there are three or four steps :

 

1. ACComponent instance

You need an ACComponent instance that you want to print. Either it is the this pointer itself or a reference that you received via ACUrlCommand or created again. Examples:

ACClass iPlusType = typeof(BSOInOrder).GetACType() as ACClass;
BSOInOrder refToPrintComp = StartComponent(iPlusType, iPlusType, null) as BSOInOrder;
refToPrintComp.AccessPrimary.NavACQueryDefinition.ACFilterColumns.FirstOrDefault()
.SetSearchValue<string>("123456789");
refToPrintComp.Search();
ACComponent refToPrintComp = ACUrlCommand("\\MyApp\\InstanceWithReports") as ACComponent;

 

2. Design (report)

You need a report from this instance that you want to print. To do this, call the method of one of the multiple overloaded GetDesign (...) methods to get a reference to ACClassDesign (the XAML code is stored in ACClassDesign.XMLDesign).

ACClassDesign designToPrint = refToPrintComp.GetDesign("MyReportName");

 

3. Print design

Call the ACComponents method PrintDesign which encapsulate the another step 3.ReportData and step 4.Printing with the report generator

int copies = 5;
Msg possibleError = refToPrintComp.PrintDesign(designToPrint, "hpLaserJetA4", copies , false);

 

OR

 

3. ReportData

Call the static method ReportData.BuildReportData () to provide the report data for the report generator. Pass the reference of the ACComponent to be printed (refToPrintComp). Please note that the instance is cloned and confirmed in the out variable cloneInstantiated:

bool cloneInstantiated = false;
ReportData reportData = ReportData.BuildReportData(out cloneInstantiated,
Global.CurrentOrList.Current, refToPrintComp, null, designToPrint);

 

4. Printing with the report generator

Finally you need an instance of the report generator ( class VBBSOReport ). Either you have a permanent reference somewhere in the application tree or you can create your own during runtime. Call the Print method and pass the design and report data:

ACClass reportEType = typeof(VBBSOReport).GetACType() as ACClass;
VBBSOReport reportEngine = StartComponent(reportEType, reportEType, null) as VBBSOReport;
int copies = 5;
reportEngine.Print(designToPrint, false, "hpLaserJetA4", reportData, copies);