-
Notifications
You must be signed in to change notification settings - Fork 2
/
MergeProcessor.vb
171 lines (146 loc) · 9.01 KB
/
MergeProcessor.vb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
Imports System.Collections.Generic
Imports DevExpress.XtraRichEdit
Imports DevExpress.XtraRichEdit.API.Native
Namespace MasterDetailExample
Friend Class MergeProcessor
Private mainRichEdit As RichEditDocumentServer = New RichEditDocumentServer()
Private suppllierRichEdit As RichEditDocumentServer = New RichEditDocumentServer()
Private productRichEdit As RichEditDocumentServer = New RichEditDocumentServer()
Private ordersRichEdit As RichEditDocumentServer = New RichEditDocumentServer()
Private resultRichEdit As RichEditDocumentServer = New RichEditDocumentServer()
Private ds As SupplierCollection
Private dataDetailedForProducts As ProductCollection
Private dataDetailedForOrders As OrderDetailCollection
Private Shared fakeDataSource As List(Of Integer) = DataHelper.CreateFakeDataSource()
Private supplierID As Integer = -1
Private productID As Integer = -1
Public Sub New()
' Subscribe to the CalculateDocumentVariable event that triggers the master-detail report generation
AddHandler resultRichEdit.CalculateDocumentVariable, New CalculateDocumentVariableEventHandler(AddressOf resultRichEdit_CalculateDocumentVariable)
' Load main template
mainRichEdit.LoadDocument("main.rtf")
' Create project's data source
ds = DataHelper.CreateData()
' Load templates and specify data sources for RichEdit servers.
suppllierRichEdit.LoadDocument("supplier.rtf")
suppllierRichEdit.Options.MailMerge.DataSource = ds
productRichEdit.LoadDocument("detail.rtf")
productRichEdit.Options.MailMerge.DataSource = ds
productRichEdit.Options.MailMerge.DataMember = "Products"
ordersRichEdit.LoadDocument("detaildetail.rtf")
ordersRichEdit.Options.MailMerge.DataSource = ds
ordersRichEdit.Options.MailMerge.DataMember = "Products.OrderDetails"
End Sub
'#Region "#startmailmerge"
' 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
'#End Region ' #startmailmerge
'#Region "#secondstage"
' 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 Equals(e.VariableName, "Supplier") Then
' Create a text engine to process a document after the mail merge.
Dim richServerMaster As RichEditDocumentServer = 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
'#End Region ' #secondstage
'#Region "#thirdstage"
' 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
If supplierID <> currentSupplierID Then
' Get data source that contains products for the specified supplier.
dataDetailedForProducts = GetProductsDataFilteredbySupplier(currentSupplierID)
supplierID = currentSupplierID
End If
If Equals(e.VariableName, "Product") Then
' Create a text engine to process a document after the mail merge.
Dim richServerDetail As RichEditDocumentServer = 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
'#End Region ' #thirdstage
'#Region "#fourthstage"
' 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
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 Equals(e.VariableName, "OrderDetails") Then
Dim richServerDetailDetail As RichEditDocumentServer = 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
'#End Region ' #fourthstage
'#Region "Helper Methods"
Protected Friend Overridable Function GetProductsDataFilteredbySupplier(ByVal supplierID As Integer) As ProductCollection
Dim products As ProductCollection = New ProductCollection()
For Each s As Supplier In ds
If s.SupplierID = supplierID Then
products.AddRange(s.Products)
End If
Next
Return products
End Function
Protected Friend Overridable Function GetOrderDataFilteredbyProductAndSupplier(ByVal productID As Integer) As OrderDetailCollection
Dim orders As OrderDetailCollection = New OrderDetailCollection()
For Each p As Product In dataDetailedForProducts
If p.ProductID = productID Then
orders.AddRange(p.OrderDetails)
End If
Next
Return orders
End Function
Protected Friend Overridable Function GetID(ByVal value As String) As Integer
Dim result As Integer
If Integer.TryParse(value, result) Then Return result
Return -1
End Function
'#End Region ' Helper Methods
End Class
End Namespace