-
Notifications
You must be signed in to change notification settings - Fork 2
/
MergeProcessor.cs
186 lines (162 loc) · 8.78 KB
/
MergeProcessor.cs
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
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using DevExpress.XtraRichEdit;
using DevExpress.XtraRichEdit.API.Native;
namespace MasterDetailExample
{
class MergeProcessor
{
RichEditDocumentServer mainRichEdit = new RichEditDocumentServer();
RichEditDocumentServer suppllierRichEdit = new RichEditDocumentServer();
RichEditDocumentServer productRichEdit = new RichEditDocumentServer();
RichEditDocumentServer ordersRichEdit = new RichEditDocumentServer();
RichEditDocumentServer resultRichEdit = new RichEditDocumentServer();
SupplierCollection ds;
ProductCollection dataDetailedForProducts;
OrderDetailCollection dataDetailedForOrders;
static List<int> fakeDataSource = DataHelper.CreateFakeDataSource();
int supplierID = -1;
int productID = -1;
public MergeProcessor()
{
// Subscribe to the CalculateDocumentVariable event that triggers the master-detail report generation
resultRichEdit.CalculateDocumentVariable += new CalculateDocumentVariableEventHandler(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";
}
#region #startmailmerge
// Start the process by merging main template into the document contained within the resultRichEdit server.
public void 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);
}
#endregion #startmailmerge
#region #secondstage
// Second stage. For each Supplier ID create a detailed document that will be inserted in place of the DOCVARIABLE field.
void resultRichEdit_CalculateDocumentVariable(object sender, CalculateDocumentVariableEventArgs e)
{
if (e.VariableName == "Supplier") {
// Create a text engine to process a document after the mail merge.
RichEditDocumentServer richServerMaster = new RichEditDocumentServer();
// Provide a procedure for further processing
richServerMaster.CalculateDocumentVariable += 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);
richServerMaster.CalculateDocumentVariable -= richServerMaster_CalculateDocumentVariable;
// Return the document to insert.
e.Value = richServerMaster;
// Required to use e.Value. Otherwise it will be ignored.
e.Handled = true;
}
}
#endregion #secondstage
#region #thirdstage
// Third stage. For each Product ID create a detailed document that will be inserted in place of the DOCVARIABLE field.
void richServerMaster_CalculateDocumentVariable(object sender, CalculateDocumentVariableEventArgs e)
{
int currentSupplierID = GetID(e.Arguments[0].Value);
if (currentSupplierID == -1)
return;
if (supplierID != currentSupplierID) {
// Get data source that contains products for the specified supplier.
dataDetailedForProducts = GetProductsDataFilteredbySupplier(currentSupplierID);
supplierID = currentSupplierID;
}
if (e.VariableName == "Product") {
// Create a text engine to process a document after the mail merge.
RichEditDocumentServer richServerDetail = new RichEditDocumentServer();
// Specify data source for mail merge.
MailMergeOptions options = 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.
richServerDetail.CalculateDocumentVariable += 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);
richServerDetail.CalculateDocumentVariable -= 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;
}
}
#endregion #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.
void richServerDetail_CalculateDocumentVariable(object sender, CalculateDocumentVariableEventArgs e)
{
int currentProductID = GetID(e.Arguments[0].Value);
if (currentProductID == -1)
return;
if (productID != currentProductID) {
// 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;
}
if (e.VariableName == "OrderDetails") {
RichEditDocumentServer richServerDetailDetail = new RichEditDocumentServer();
MailMergeOptions options = ordersRichEdit.CreateMailMergeOptions();
options.DataSource = dataDetailedForOrders;
options.MergeMode = MergeMode.JoinTables;
ordersRichEdit.MailMerge(options, richServerDetailDetail);
e.Value = richServerDetailDetail;
e.Handled = true;
}
}
#endregion #fourthstage
#region Helper Methods
protected internal virtual ProductCollection GetProductsDataFilteredbySupplier(int supplierID)
{
ProductCollection products = new ProductCollection();
foreach (Supplier s in ds) {
if (s.SupplierID == supplierID) {
products.AddRange(s.Products);
}
}
return products;
}
protected internal virtual OrderDetailCollection GetOrderDataFilteredbyProductAndSupplier(int productID)
{
OrderDetailCollection orders = new OrderDetailCollection();
foreach (Product p in dataDetailedForProducts) {
if (p.ProductID == productID) {
orders.AddRange(p.OrderDetails);
}
}
return orders;
}
protected internal virtual int GetID(string value)
{
int result;
if (Int32.TryParse(value, out result))
return result;
return -1;
}
#endregion Helper Methods
}
}