Skip to main content
A newer version of this page is available. .

Master-Detail Report

  • 9 minutes to read

This article describes how the Mail Merge feature enhanced with DOCVARIABLE specifics allows users to accomplish complex tasks such as creating Master-Detail reports.

In this example, the report is generated using four templates: Main, Master, Detail, and DetailDetail containing DOCVARIABLE fields. A RichEditDocumentServer instance is created on each data level for holding the corresponding template and for calculating in the RichEditDocumentServer.CalculateDocumentVariable event handler. As a result, all intermediate documents are combined into a single report, which is passed to the parent document to substitute the initial DOCVARIABLE field.

The following image displays the result:

OfficeFileAPI_MasterDetail_Result

The steps below provide more detailed information about how to process each part of a master-detail report.

Main Template

The main template is the document without MERGEFIELD fields. It may contain a logo, standard header and footer, and all the parts required for a corporative design and layout. The template’s DOCVARIABLE field indicates where the Master template is inserted. Use the FieldCollection.Create method to insert a field into the desired position in the document.

Initiate the mail merge process with empty data. Assign the control to a mock data source and call the Document.MailMerge method with the resulting control’s document or a file set as the destination (in this example, the result is passed to the resultRichEdit).

' Start the process by merging main template into the document contained within the resultRichEdit server.
Public Sub Start()
    ' Since the main template contains no merge fields requiring no merge data, provide a fake data source.
    ' Otherwise mailmerge will not start.
    mainRichEdit.Options.MailMerge.DataSource = fakeDataSource
    ' Trigger the multistage process. After the first mailmerge the CalculateDocumentVariable event
    'for the resultRichEdit server fires.
    mainRichEdit.MailMerge(resultRichEdit.Document)
    resultRichEdit.SaveDocument("result.docx", DocumentFormat.OpenXml)
End Sub

Master Template

The destination control receives the Main document and fires the RichEditDocumentServer.CalculateDocumentVariable event. Handle this event the following way to create a master part and insert it into the document:

  1. Make sure that the event is fired for the required field (by checking the CalculateDocumentVariableEventArgs.VariableName value).
  2. Create a new RichEditDocumentServer instance to create a report and pass it to the event sender using the CalculateDocumentVariableEventArgs.Value property.
  3. Subscribe the created document server instance to the RichEditControl.CalculateDocumentVariable event to process the detail part of the report.
  4. Call the Document.MailMerge method to merge the Master template and obtain the source document with the corresponding data.
  5. Pass the document to insert to the e.Value property.
  6. Set the Handled property to true. Otherwise, the previous step is ignored.
' Second stage. For each Supplier ID create a detailed document that will be inserted in place of the DOCVARIABLE field.
Private Sub resultRichEdit_CalculateDocumentVariable(ByVal sender As Object, ByVal e As CalculateDocumentVariableEventArgs)
    If e.VariableName = "Supplier" Then
        ' Create a text engine to process a document after the mail merge.
        Dim richServerMaster As New RichEditDocumentServer()
        ' Provide a procedure for further processing
        AddHandler richServerMaster.CalculateDocumentVariable, AddressOf richServerMaster_CalculateDocumentVariable
        ' Create a merged document using the Supplier template. The document will contain DOCVARIABLE fields with ProductID arguments. 
        ' The CalculateDocumentVariable event for the richServerMaster fires.
        suppllierRichEdit.MailMerge(richServerMaster)
        RemoveHandler richServerMaster.CalculateDocumentVariable, AddressOf richServerMaster_CalculateDocumentVariable
        ' Return the document to insert.
        e.Value = richServerMaster
        ' Required to use e.Value. Otherwise it will be ignored.
        e.Handled = True
    End If
End Sub

Detail Template

After the mail merge, the document created from the Master template is loaded into the RichEditDocumentServer instance, and the RichEditDocumentServer.CalculateDocumentVariable event fires. Handle the event to compose the Detail template:

  1. Make sure that the event is fired for the required field (by checking the CalculateDocumentVariableEventArgs.VariableName value);
  2. Create new RichEditDocumentServer instance.
  3. This template contains a master-detail table header. The resulting table is composed of separate tables. Use the MergeMode.JoinTables option to make the tables continuous. When not using tables, assigning this value to the MailMergeOptions.MergeMode property results in an incorrect layout.
  4. Subscribe to the Document.CalculateDocumentVariable event of the current RichEditDocumentServer instance for further processing. This step is required if the Detail template contains any DOCVARIABLE fields. In this example, the Document.CalculateDocumentVariable event is used to insert and format the UnitPrice field.
  5. Call the Document.MailMerge method to merge the Detail template.
  6. Pass the document to insert to the e.Value property.
  7. Set the Handled property to true. Otherwise, the previous step is ignored.
' Third stage. For each Product ID create a detailed document that will be inserted in place of the DOCVARIABLE field.
Private Sub richServerMaster_CalculateDocumentVariable(ByVal sender As Object, ByVal e As CalculateDocumentVariableEventArgs)
    Dim currentSupplierID As Integer = GetID(e.Arguments(0).Value)
    If currentSupplierID = -1 Then
        Return
    End If

    If supplierID <> currentSupplierID Then
        ' Get data source that contains products for the specified supplier.
        dataDetailedForProducts = GetProductsDataFilteredbySupplier(currentSupplierID)
        supplierID = currentSupplierID
    End If

    If e.VariableName = "Product" Then
        ' Create a text engine to process a document after the mail merge.
        Dim richServerDetail As New RichEditDocumentServer()
        ' Specify data source for mail merge.
        Dim options As MailMergeOptions = productRichEdit.CreateMailMergeOptions()
        options.DataSource = dataDetailedForProducts
        ' Specify that the resulting table should be joined with the header table.
        ' Do not specify this option if calculated fields are not within table cells.
        options.MergeMode = MergeMode.JoinTables
        ' Provide a procedure for further processing.
        AddHandler richServerDetail.CalculateDocumentVariable, AddressOf richServerDetail_CalculateDocumentVariable
        ' Create a merged document using the Product template. The document will contain DOCVARIABLE fields with OrderID arguments. 
        ' The CalculateDocumentVariable event for the richServerDetail fires.
        productRichEdit.MailMerge(options, richServerDetail)
        RemoveHandler richServerDetail.CalculateDocumentVariable, AddressOf richServerDetail_CalculateDocumentVariable
        ' Return the document to insert.
        e.Value = richServerDetail
        ' This setting is required for inserting e.Value into the source document. Otherwise it will be ignored.
        e.Handled = True
    End If
End Sub

Detail-Detail Template

This is the final merging part. Handle the RichEditDocumentServer.CalculateDocumentVariable event to compose this part as follows:

  1. Make sure that the event is fired for the required field (by checking the CalculateDocumentVariableEventArgs.VariableName value).
  2. Create new RichEditDocumentServer and MailMergeOptions instances.
  3. This template also contains a master-detail table header. Set the MailMergeOptions.MergeMode property to MergeMode.JoinTables to make the tables continuous. When not using tables, assigning this value to the MergeMode property results in an incorrect layout.
  4. Provide the data source for merging. In this example, the data is filtered by supplier, then retrieved and passed as the RichEditMailMergeOptions.DataSource property value.
  5. Call the Document.MailMerge method with given mail merge options to merge the Detail-Detail template.
  6. Pass the document to insert to the e.Value property.
  7. Set the Handled property to true. Otherwise, the previous step is ignored.
' Fourth stage. For each Order ID create a detailed document that will be inserted in place of the DOCVARIABLE field.
' This is the final stage and the Product.Orders template does not contain DOCVARIABLE fields. So, further processing is not required.
Private Sub richServerDetail_CalculateDocumentVariable(ByVal sender As Object, ByVal e As CalculateDocumentVariableEventArgs)
    Dim currentProductID As Integer = GetID(e.Arguments(0).Value)
    If currentProductID = -1 Then
        Return
    End If

    If productID <> currentProductID Then
        ' Get data source that contains orders for the specified product. 
        ' The data source is obtained from the data already filtered by supplier.
        dataDetailedForOrders = GetOrderDataFilteredbyProductAndSupplier(currentProductID)
        productID = currentProductID
    End If

    If e.VariableName = "OrderDetails" Then

        Dim richServerDetailDetail As New RichEditDocumentServer()
        Dim options As MailMergeOptions = ordersRichEdit.CreateMailMergeOptions()
        options.DataSource = dataDetailedForOrders
        options.MergeMode = MergeMode.JoinTables
        ordersRichEdit.MailMerge(options, richServerDetailDetail)
        e.Value = richServerDetailDetail
        e.Handled = True
    End If
End Sub
See Also