Guides/LayeredSubtotaling.md
... ...
@@ -45,7 +45,12 @@ public class CustomAdHocConfig : FileSystemAdHocConfig
45 45
46 46
public override string PerformCustomRendering(string initialHtml)
47 47
{
48
- return myLayeredSubtotaling.PerformCustomRendering(initialHtml);
48
+ string outputHtml = myLayeredSubtotaling.PerformCustomRendering(initialHtml);
49
+
50
+ //Uncomment the following lines if you need to manually clean things up after processing
51
+ //LayeredSubtotaling.CleanUpDeltas();
52
+ //myLayeredSubtotaling.ResetStep();
53
+ return outputHtml;
49 54
}
50 55
}
51 56
... ...
@@ -56,12 +61,20 @@ public class LayeredSubtotaling
56 61
{
57 62
public bool hasSubtotals = false;
58 63
static Dictionary<string, List<object>> deltas = new Dictionary<string, List<object>>();
59
- bool firstPass = true;
60
- VisualGroupStyle targetVGStyle;
64
+ VisualGroupStyle _targetVGStyle;
65
+ ReportSetRenderingStep currentStep;
66
+
67
+ enum ReportSetRenderingStep
68
+ {
69
+ ReportTableStep = 0,
70
+ FullCountStep = 1,
71
+ TotalsStep = 2
72
+ }
61 73
62 74
public LayeredSubtotaling(VisualGroupStyle targetVGStyle)
63 75
{
64 76
_targetVGStyle = targetVGStyle;
77
+ currentStep = ReportSetRenderingStep.ReportTableStep;
65 78
}
66 79
67 80
/// <summary>
... ...
@@ -69,7 +82,11 @@ public class LayeredSubtotaling
69 82
/// </summary>
70 83
public void DoSubtotalingForVG(System.Data.DataSet ds, string reportPart)
71 84
{
72
- if (firstPass && !String.IsNullOrEmpty(reportPart))
85
+ //Nothing to do. This isn't a report data set
86
+ if (String.IsNullOrEmpty(reportPart))
87
+ return;
88
+ //We only want to do the main processing when we have the actual data
89
+ if (currentStep == ReportSetRenderingStep.ReportTableStep)
73 90
{
74 91
string header, where;
75 92
List<object> dataColumns = new List<object>();
... ...
@@ -139,11 +156,12 @@ public class LayeredSubtotaling
139 156
}
140 157
}
141 158
142
- // If subtotaling is enabled, toggle first pass so the subtotal loop does wipe out custom totals.
159
+ // If subtotaling Is enabled, there are three times during report execution when ProcessDataSet is called, otherwise it is called twice
160
+ // We can cycle through the enum values to ensure every execution works properly
143 161
if (hasSubtotals)
144
- {
145
- firstPass = !firstPass;
146
- }
162
+ currentStep = (ReportSetRenderingStep)(((int)(currentStep + 1)) % 3);
163
+ else
164
+ currentStep = (ReportSetRenderingStep)(((int)(currentStep + 1)) % 2);
147 165
}
148 166
149 167
/// <summary>
... ...
@@ -233,6 +251,22 @@ public class LayeredSubtotaling
233 251
}
234 252
235 253
/// <summary>
254
+ /// If we need to, we can clear out the deltas manually to free up memory
255
+ /// </summary>
256
+ public static void CleanUpDeltas()
257
+ {
258
+ deltas.Clear();
259
+ }
260
+
261
+ /// <summary>
262
+ /// Just in case something misfires, we can reset the rendering step manually
263
+ /// </summary>
264
+ public void ResetStep()
265
+ {
266
+ currentStep = ReportSetRenderingStep.ReportTableStep;
267
+ }
268
+
269
+ /// <summary>
236 270
/// PrintFinalDeltas is called to in the case of level 1 delta changes. It makes sure all deltas get printed out,
237 271
/// not just the level 1.
238 272
/// </summary>
... ...
@@ -314,7 +348,12 @@ Public Class CustomAdHocConfig
314 348
End Sub
315 349
316 350
Public Overrides Function PerformCustomRendering(initialHtml As String) As String
317
- Return myLayeredSubtotaling.PerformCustomRendering(initialHtml)
351
+ Dim outputHtml = myLayeredSubtotaling.PerformCustomRendering(initialHtml)
352
+
353
+ 'Uncomment the following lines if you need to manually clean things up after processing
354
+ 'LayeredSubtotaling.CleanUpDeltas()
355
+ 'myLayeredSubtotaling.ResetStep()
356
+ Return outputHtml
318 357
End Function
319 358
End Class
320 359
... ...
@@ -324,18 +363,30 @@ End Class
324 363
Public Class LayeredSubtotaling
325 364
Public hasSubtotals As Boolean = False
326 365
Shared deltas As New Dictionary(Of String, List(Of Object))()
327
- Dim firstPass As Boolean = True
328 366
Dim _targetVGStyle As VisualGroupStyle
367
+ Dim currentStep As ReportSetRenderingStep
368
+
369
+ Enum ReportSetRenderingStep
370
+ ReportTableStep = 0
371
+ FullCountStep = 1
372
+ TotalsStep = 2
373
+ End Enum
329 374
330 375
Sub New(targetVGStyle As VisualGroupStyle)
331 376
_targetVGStyle = targetVGStyle
377
+ currentStep = ReportSetRenderingStep.ReportTableStep
332 378
End Sub
333 379
334 380
' <summary>
335 381
' Overrides base version to support custom totaling of various deltas in the report.
336 382
' </summary>
337 383
Public Sub DoSubtotalingForVG(ds As DataSet, reportPart As String)
338
- If firstPass AndAlso Not String.IsNullOrEmpty(reportPart) Then
384
+ ' Nothing to do. This isn't a report data set
385
+ If String.IsNullOrEmpty(reportPart) Then
386
+ Return
387
+ End If
388
+ ' We only want to do the main processing when we have the actual data
389
+ If currentStep = ReportSetRenderingStep.ReportTableStep Then
339 390
Dim header, where As String
340 391
Dim dataColumns As New List(Of Object)()
341 392
Dim dataHeaders As New Dictionary(Of String, String)()
... ...
@@ -359,14 +410,15 @@ Public Class LayeredSubtotaling
359 410
'Otherwise, add the item, separated by a comma.
360 411
header += ", " & row(column).ToString()
361 412
where += " AND [" & column.ToString() & "] = '" & row(column) & "'"
413
+ End If
362 414
363
- 'If the header Is already in the list, ignore it And move on.
364
- If (Not dataHeaders.ContainsKey(header)) Then
365
- dataHeaders.Add(header, where)
366
- End If
415
+ 'If the header Is already in the list, ignore it And move on.
416
+ If (Not dataHeaders.ContainsKey(header)) Then
417
+ dataHeaders.Add(header, where)
367 418
End If
368
- 'Otherwise this Is a data column And add it to that data structure.
419
+
369 420
ElseIf Not dataColumns.Contains(column) AndAlso row(column).GetType() IsNot GetType(DBNull) Then
421
+ 'Otherwise this Is a data column And add it to that data structure.
370 422
dataColumns.Add(column)
371 423
End If
372 424
Next
... ...
@@ -389,9 +441,12 @@ Public Class LayeredSubtotaling
389 441
Next
390 442
End If
391 443
End If
392
- ' If subtotaling Is enabled, toggle first pass so the subtotal loop does wipe out custom totals.
444
+ ' If subtotaling Is enabled, there are three times during report execution when ProcessDataSet is called, otherwise it is called twice
445
+ ' We can cycle through the enum values to ensure every execution works properly
393 446
If hasSubtotals Then
394
- firstPass = Not firstPass
447
+ currentStep = DirectCast((currentStep + 1) Mod 3, ReportSetRenderingStep)
448
+ Else
449
+ currentStep = DirectCast((currentStep + 1) Mod 2, ReportSetRenderingStep)
395 450
End If
396 451
End Sub
397 452
... ...
@@ -470,6 +525,20 @@ Public Class LayeredSubtotaling
470 525
End Function
471 526
472 527
' <summary>
528
+ ' If we need to, we can clear out the deltas manually to free up memory
529
+ ' </summary>
530
+ Public Shared Sub CleanUpDeltas()
531
+ deltas.Clear()
532
+ End Sub
533
+
534
+ ' <summary>
535
+ ' Just in case something misfires, we can reset the rendering step manually
536
+ ' </summary>
537
+ Public Sub ResetStep()
538
+ currentStep = ReportSetRenderingStep.ReportTableStep
539
+ End Sub
540
+
541
+ ' <summary>
473 542
' PrintFinalDeltas Is called to in the case of level 1 delta changes. It makes sure all deltas get printed out,
474 543
' Not just the level 1.
475 544
' </summary>