{"id":139,"date":"2008-03-03T20:46:00","date_gmt":"2008-03-03T20:46:00","guid":{"rendered":"\/lisa\/post\/2008\/03\/03\/Report-Preprocessing-SQL-Server-Reporting-Server-Group-PageTotals-Walkthrough-Part-I-the-RDL-and-the-Server.aspx"},"modified":"2008-03-03T20:46:00","modified_gmt":"2008-03-03T20:46:00","slug":"report-preprocessing-sql-server-reporting-server-group-pagetotals-walkthrough-part-i-the-rdl-and-the-server","status":"publish","type":"post","link":"https:\/\/spacefold.com\/lisa\/2008\/03\/03\/report-preprocessing-sql-server-reporting-server-group-pagetotals-walkthrough-part-i-the-rdl-and-the-server\/","title":{"rendered":"Report Preprocessing: SQL Server Reporting Server Group PageTotals Walkthrough, Part I: the RDL and the Server"},"content":{"rendered":"<p>\nAnother boring title for another important topic.&nbsp;\n<\/p>\n<p>\nWhen I wrote <a href=\"\/lisa\/2007\/09\/15\/Reset-On-Group-(Page-X-of-XX-in-a-group-within-a-total-Y-of-YY-for-the-report)-SQL-Reporting-Services-Style-\/\">https:\/\/spacefold.com\/lisa\/2007\/09\/15\/Reset-On-Group-(Page-X-of-XX-in-a-group-within-a-total-Y-of-YY-for-the-report)-SQL-Reporting-Services-Style-<\/a><a href=\"\/lisa\/Reset-On-Group-(Page-X-of-XX-in-a-group%2c-within-a-total-Y-of-YY-for-the-report)%2c-SQL-Reporting-Services-Style-\/\"><\/a>, as usual I thought that was the end of it.&nbsp;\n<\/p>\n<p>\nWell, not exactly.&nbsp; I thought I was finished writing about <em>that<\/em> technique, and that I was going to go on and write more about debugging techniques and other related subjects in RS.&nbsp; It&#39;s a subject dear to my heart and, I thought, of more general interest that the specialized trick involved in reset-pagenumbers-on-group and group page totals.\n<\/p>\n<p>\nAs usual, I was wrong &#8212;&nbsp;&nbsp;this time on at least two&nbsp;counts.&nbsp;\n<\/p>\n<p>\nI was wrong to think I was going to have&nbsp;enough time&nbsp;to blog in the next couple of months to start the extended report debugging technique&nbsp;series I had in mind (although I did allude to it briefly <a href=\"\/lisa\/2007\/09\/15\/Reset-On-Group-(Page-X-of-XX-in-a-group-within-a-total-Y-of-YY-for-the-report)-SQL-Reporting-Services-Style-\/\" title=\"Dynamic SQL post with debug implications\">here<\/a>).&nbsp; And I was wrong to think that people weren&#39;t going to need or &nbsp;<a href=\"http:\/\/forums.microsoft.com\/MSDN\/ShowPost.aspx?PostID=1807270&amp;SiteID=1\" title=\"MSDN forum thread on this subject keeps growing\">want a more explicit discussion of how can you do this<\/a>&nbsp;specific thing.\n<\/p>\n<p>\nSo I sat down (three weeks ago) to write down the proper code for a full-blown walkthrough, and realized I had no idea how many different areas were involved and how long it was going to take me to explain. My heart (and free time) totally failed me.\n<\/p>\n<p>\nOK, I&#39;m ready now.&nbsp; I may be posting in separate parts.\n<\/p>\n<h3>Reminder: the goal<\/h3>\n<p>\nWe have a group or more than one group in an RDL. One group has &quot;pagebreak after&quot; set for it. We want to be able to write some expression like this in our page header:\n<\/p>\n<p class=\"code\">\n=<span style=\"color: #a31515\">&quot;Page &quot;<\/span>&amp; Globals!PageNumber &amp;<span style=\"color: #a31515\">&quot; of &quot;<\/span>&amp; Globals!TotalPages &amp;<span style=\"color: #a31515\">&quot; Report Total &quot;<\/span> &amp; vbCRLF &amp; <br \/>\n<span style=\"color: #a31515\">&nbsp; &quot;Page &quot;<\/span> &amp; [Group Page Number] &amp; <span style=\"color: #a31515\">&quot; of &quot;<\/span> [Group Total Pages] <span style=\"color: #a31515\">&quot; for &quot;<\/span> &amp;&nbsp;[GroupLabel]\n<\/p>\n<p>\n<br \/>\nShould be a breeze, right?\n<\/p>\n<h4>Well&#8230; you can&#39;t.<\/h4>\n<p>\nWell, as you may remember from the previous discussions I&#39;ve linked to above, both here and on the forums, there&#39;s no easy way to do this in RS, partly because the page headers are figured out at a different time from the body content, I think.&nbsp; There&#39;s a good reason for this: pagination is going to be different for each renderer.\n<\/p>\n<p>\nSo, and again please refer to the other posts for background, you have to hack it.&nbsp; To get the group page numbers you can keep a collection of values yourself, and feed these to the page header.&nbsp; To get group total page numbers you need to preprocess the report, so that you know what the group totals are at the end of the preprocess run, keeping them in a collection you can reference on the second run.\n<\/p>\n<p>\nNow, we&#39;re going to look into all the things you have to do, in order to do that simple thing.\n<\/p>\n<h3>Setting the stage for this walkthrough<\/h3>\n<p>\nTo simplify but cover all the necessary bases, I had to make some choices here:\n<\/p>\n<ul>\n<li>I have chosen to do this in a server-mode report, because that seemed to me to be the more significant case and offered the more difficult challenges, so I wanted to be sure and explain them.<\/li>\n<li>I have chosen to do this from the point of view of an ASP.NET client rather than a Winforms client &#8212; ditto.<\/li>\n<li>I&#39;m not using a custom DLL, because&nbsp;that&#39;s beyond scope in this discussion.&nbsp; I&#39;m going to do everything in the custom code you can embed in the RDL. If you do use a custom DLL, it will actually make one step of this much more rational (whether you choose an XML approach or a database approach): setting the server security permissions properly.&nbsp; Also, the code I&#39;ve written here is pretty generic, so it is a good candidate for custom DLL usage.&nbsp; If you want to do this in a local report, you might like to look at <a href=\"http:\/\/blogs.msdn.com\/mosharaf\/archive\/2005\/12\/20\/LocalReportCustomCode\/\" target=\"_blank\" title=\"Blog post on local report custom code\" rel=\"noopener\">this post on using custom code in a local report<\/a>.&nbsp; If you want to do this in a custom DLL, you might like to look at <a href=\"http:\/\/www.code-magazine.com\/article.aspx?quickid=0701061&amp;page=2\" title=\"CoDe magazine article on custom code DLLs for data access in RS\">this article on writing a custom code dll&nbsp;<\/a>. Note that there are many different articles and posts on this subject, but I&#39;m pointing to this one because it also looks at accessing database values in the custom code, which you might want to do as well (see next point).<\/li>\n<li>I have chosen to keep my preprocess information in an XML file, while in reality you might want to send the values to a database instead.&nbsp;This was largely for clarity\/streamlining in the example, although I like to work in XML for stuff like this.&nbsp; Again, taking the database route might actually make things easier for you than what you see here. There are some caveats you&#39;ll see in this walkthrough regarding the shared variables, which you might be able to get around if you persisted everything to a database, although I&#39;m not sure it would work to try to do things there.&nbsp; See next point.<\/li>\n<li>I am showing the code for two different renderings: HTML and PDF.&nbsp; This seemed to me to cover the two significant types of rendering from the point of view of pagination: one interactive layout and one &quot;printable&quot; layout. Again, each renderer paginates differently and may internally do things in a different order. <br \/>\n\tShowing the code for two styles of rendering may have added a little complexity to this code that you would not need. But if you do write it, I recommend you add a parameter representing &quot;which rendering&quot; to your report, just in case.<\/li>\n<\/ul>\n<h4>Let&#39;s be bad guys<\/h4>\n<p>\nTime&nbsp;to start hacking away at these tasks.&nbsp; We&#39;re going to start with the RDL in this installment, and&nbsp;in a followup post I&#39;ll cover the client side.\n<\/p>\n<h3>Our reporting&nbsp;source&nbsp;data<\/h3>\n<p>\nWe&#39;re going to use&nbsp;the MySQL World database, my favorite for tutorials, because it&#39;s a simple, clear structure.&nbsp; You don&#39;t need the actual database for this (although you can <a href=\"http:\/\/dev.mysql.com\/doc\/\" target=\"_blank\" title=\"MySQL docs download page\" rel=\"noopener\">d\/l it from here<\/a> for MySQL, or <a href=\"\/wp-content\/downloads\/MSWorld.zip\" target=\"_blank\" title=\"MSWorld.zip with SQL script\" rel=\"noopener\">use my variant of the MySQL script<\/a> if you&#39;re only running SQL Server for your data sources).&nbsp; All you really need to know is that, in the example report, we are reporting on countries and their languages. To help you visualize, the SQL for single dataset in the report looks like this:\n<\/p>\n<p class=\"code\">\nSELECT&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br \/>\n&nbsp;&nbsp; Country.Name, Country.Continent, Country.Region, CountryLanguage.Language<br \/>\nFROM&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CountryLanguage INNER JOIN<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Country ON CountryLanguage.CountryCode = Country.Code<br \/>\nORDER BY Country.Region, Country.Name, CountryLanguage.Language\n<\/p>\n<p>\nSee? <a href=\"\/lisa\/wp-non\/migrated\/CountryLanguageDataSet.png\" target=\"_blank\" rel=\"noopener\"><img loading=\"lazy\" decoding=\"async\" src=\"\/lisa\/wp-non\/migrated\/preview.png\" border=\"0\" alt=\"\" title=\"See what I'm talking \nabout?\" width=\"12\" height=\"12\" align=\"textTop\" \/><\/a>&nbsp; Nice and simple.\n<\/p>\n<h3>Our reporting goal<\/h3>\n<p>\nOur report design has an outer group on Regions, with&nbsp;page-break-after set for it, and an inner group on country name.&nbsp;Having multiple groups&nbsp;is not relevant to the example, but I set it up this way just to make sure a more complex case would work, and also because this was the scenario for one of the MSDN requests for information about this.&nbsp;&nbsp;\n<\/p>\n<p>\nI&#39;ve included the Continent name above the Region information in the outer group header, for no really good reason except it looked good there.\n<\/p>\n<p>\nSo the report layout we&#39;re looking for is something like this:\n<\/p>\n<table border=\"0\">\n<tbody>\n<tr>\n<td colspan=\"2\"><strong>SQL World Languages<\/strong> <font color=\"#ff0000\"><br \/>\n\t\t\tPage 3 of 30 Report Total<br \/>\n\t\t\tPage 1 of 12 for Eastern Africa Region<\/font><\/td>\n<\/tr>\n<tr>\n<td colspan=\"2\"><strong>Africa<\/strong><\/td>\n<\/tr>\n<tr bgcolor=\"#333330\">\n<td><font color=\"#ffffff\">Eastern Africa<\/font><\/td>\n<td><font color=\"#ffffff\">Language<\/font><\/td>\n<\/tr>\n<tr bgcolor=\"#0000ff\">\n<td colspan=\"2\"><font color=\"#ffffff\">Burundi<\/font><\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<td>French<\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<td>Kirundi<\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<td>Swahili<\/td>\n<\/tr>\n<tr bgcolor=\"#0000ff\">\n<td colspan=\"2\"><font color=\"#ffffff\">Comoros<\/font><\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<td>Comorian<\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<td>&#8230;<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>\n&#8230; also pretty simple.\n<\/p>\n<h3>Things (between us)&#8230; not so simple.<\/h3>\n<p>\nHere&#39;s the actual report expression I&#39;m using to get the red page number result you see in the layout above:\n<\/p>\n<p class=\"code\">\n=<font color=\"#a31515\">&quot;Page &quot;<\/font> &amp; Globals!PageNumber &amp; <font color=\"#a31515\">&quot; of &quot;<\/font>&amp; <br \/>\n&nbsp;&nbsp; Globals!TotalPages &amp; <font color=\"#a31515\">&quot; Report Total &quot;<\/font>&amp; vbCRLF &amp; <br \/>\n<font color=\"#a31515\">&nbsp;&nbsp; &quot;Page &quot;<\/font> &amp; Code.GetGroupPageNumber(<br \/>\n&nbsp;&nbsp; ReportItems!txtGroupHeaderItem.Value.ToString() ,<br \/>\n&nbsp;&nbsp; Globals!PageNumber,Globals!TotalPages, <br \/>\n&nbsp;&nbsp; Parameters!FileKey.Value, <br \/>\n&nbsp;&nbsp; Parameters!PreProcess.Value,Parameters!ExportType.Value ) &amp; <br \/>\n<font color=\"#a31515\">&nbsp;&nbsp; &quot; of &quot;<\/font>&amp; IIF(Parameters!PreProcess.Value,<font color=\"#a31515\">&quot;[PreProcessRun]&quot;<\/font>,<br \/>\n&nbsp;&nbsp; Code.ReadGroupPageTotal(Globals!TotalPages)) &amp; <br \/>\n<font color=\"#a31515\">&nbsp; &quot; for &quot;<\/font> &amp; Trim(Code.currentgroup) &amp; <font color=\"#a31515\">&quot; Region &quot;<br \/>\n<\/font>\n<\/p>\n<p>\nHmmm.&nbsp; The good news is there&#39;s only two functions in there. The first function fills out a bunch of variables and persists information if we&#39;re in the preprocess run. The second&nbsp;provides the preprocessed group total values during the second run.&nbsp; The other good news is that you don&#39;t have to call any other custom code anyplace else in the report.\n<\/p>\n<p>\nThe bad news is&#8230; obviously this takes a bit of doing.&nbsp;\n<\/p>\n<h3>Let&#39;s look at the parameters first.<\/h3>\n<p>\nI could actually have passed the parameters collection to the function instead of passing each parameter value individually, but it actually helps me to see them all individually.&nbsp;&nbsp;For one thing, that&nbsp;way I remember to tell you what they all do.&nbsp;\n<\/p>\n<p>\nThe first parameter in this report is <strong>FileKey<\/strong>.&nbsp; This string has the default value <strong>&quot;test&quot;<\/strong>. This is sort of a placeholder for a way to remind you to keep the results of different runs of this report distinct.&nbsp; My placeholder is providing a way for you to pass the name of the XML file that will hold the preprocess results, which you could generate differently for each user session.&nbsp; In your version, if you&#39;re handling persistence with SQL, you will still have to do something like this.&nbsp;\n<\/p>\n<p>\nNote that this technique will require some <strong>shared<\/strong> variables.&nbsp;&nbsp;As discussed in earlier posts on this subject, I&#39;m basing it off something that <a href=\"http:\/\/blogs.msdn.com\/chrishays\/archive\/2006\/01\/05\/ResetPageNumberOnGroup\/\" target=\"_blank\" title=\"Chris Hays' original techniques for the group page number part\" rel=\"noopener\">Chris Hays originally wrote<\/a> &#8212; and FWIW I didn&#39;t see why he needed to use <strong>shared<\/strong> until I got to the PDF case.&nbsp; If this is an issue in your case, I think there are ways to&nbsp;mitigate it; see <a href=\"http:\/\/gotreportviewer.com\/\">http:\/\/gotreportviewer.com\/<\/a>&nbsp;and look for the section on &quot;supplying RDLs as a stream&quot;.\n<\/p>\n<p>\nWhen we&#39;re all done building it, we&#39;re going to be calling this report twice, once to preprocess and once to provide results to the user. The <strong>PreProcess<\/strong> parameter tells the report which mode it&#39;s supposed to operate in. This boolean has the default value&nbsp;<strong>true<\/strong>.\n<\/p>\n<p>\nFinally, you see&nbsp;an <strong>ExportType&nbsp;<\/strong>parameter.&nbsp; This string has the default value <strong>&quot;HTML&quot;<\/strong>, with <strong>&quot;PDF&quot;<\/strong> being the other value currently accepted by my code. This is required to handle differences between rendering types that may sequence things differently.&nbsp;\n<\/p>\n<p>\nFWIW this technique was much, much simpler to prepare when I wasn&#39;t working with the PDF renderer, the HTML renderer&#39;s sequencing was fine but the PDF renderer couldn&#39;t &quot;see&quot; my activities in the order I expected.&nbsp; Much head-scratching ensued, followed by much more code than the original.\n<\/p>\n<p>\nIf you&#39;re curious, here are the&nbsp;principle differences:&nbsp;\n<\/p>\n<ul>\n<li>The original code opened a file for writing at the beginning of the preprocess report run, appended to it throughout the run, and closed it at the end.&nbsp; Seems reasonable, doesn&#39;t it?&nbsp; But the pattern-of-use I experienced with the PDF Rendered indicated that this was not a great idea.&nbsp;Things seemed to be happening out of order.&nbsp; As a result, when preprocessing, you&#39;ll see that I open and close the file on every &quot;hit&quot;. Oh well.&nbsp; <br \/>\n\tThis is another problem you might not have when persisting to a database rather than a file &#8212; or you might find that something similar happens if you try to hold onto a connection throughout the run.<\/li>\n<li>You&#39;ll see a PDFRunCount variable in this code.&nbsp; What&#39;s that about?&nbsp; It turns out that, at least when I invoked the PDF Renderer through URL Access, there were two sets of page numbers begin recorded; one for an internal HTML run and the other for the actual PDF pagination.&nbsp; I may have done something terminally stupid here, but in this code I&#39;m making sure to record only the correct values, using this indicator.<\/li>\n<\/ul>\n<h4>Now, about that code.<\/h4>\n<p>\nHere is the set of variables declared up-top in the custom code.&nbsp; Some are used to keep track of things internally, like PDFRunCount.&nbsp; But these variables can also be used directly in report expressions; you can see me doing that with <strong>Trim(Code.currentgroup)<\/strong> in the page header report expression, above.\n<\/p>\n<p class=\"code\">\n&nbsp;&nbsp;&nbsp; <span style=\"color: blue\">Public<\/span> <span style=\"color: blue\">Shared<\/span> offset <span style=\"color: blue\">As<\/span> <span style=\"color: blue\">Integer<\/span> = 0<br \/>\n&nbsp;&nbsp;&nbsp; <span style=\"color: blue\">Public<\/span> <span style=\"color: blue\">Shared<\/span> currentgroup <span style=\"color: blue\">As<\/span> <span style=\"color: blue\">String<\/span> <br \/>\n&nbsp;&nbsp;&nbsp; <span style=\"color: blue\">Public<\/span> <span style=\"color: blue\">Shared<\/span> previousgroup <span style=\"color: blue\">As<\/span> <span style=\"color: blue\">String<\/span> <br \/>\n&nbsp;&nbsp;&nbsp; <span style=\"color: blue\">Public<\/span> <span style=\"color: blue\">Shared<\/span> groupNo <span style=\"color: blue\">As<\/span> <span style=\"color: blue\">Integer<\/span> = 0 <br \/>\n&nbsp;&nbsp;&nbsp; <span style=\"color: blue\">Public<\/span> <span style=\"color: blue\">Shared<\/span> fileName <span style=\"color: blue\">As<\/span> <span style=\"color: blue\">String<\/span> <br \/>\n&nbsp;&nbsp;&nbsp; <span style=\"color: blue\">Public<\/span> <span style=\"color: blue\">Shared<\/span> PDFRunCount <span style=\"color: blue\">As<\/span> <span style=\"color: blue\">Integer<\/span> = 0 <br \/>\n&nbsp;&nbsp;&nbsp; <span style=\"color: blue\">Dim<\/span> sw <span style=\"color: blue\">As<\/span> System.IO.StreamWriter <br \/>\n&nbsp;&nbsp;&nbsp; <span style=\"color: blue\">Dim<\/span> doc <span style=\"color: blue\">As<\/span> System.Xml.XmlDocument\n<\/p>\n<p>\nHere&#39;s the first function, which collects group information, returns the current group&#39;s page number, and persists data between the runs so that the second run has group page totals.&nbsp; It looks alarming, but actually it&#39;s pretty straightforward.&nbsp;\n<\/p>\n<p>\nWhere you see &quot;c:\\temp&quot; for a file path below, you will want to make sure you are looking at a path that your report code has permissions to write &#8212; wherever that is, is okay (and again this would be irrelevant if you persist to a database).\n<\/p>\n<p class=\"code\">\n&nbsp;&nbsp;&nbsp; <span style=\"color: blue\">Public<\/span> <span style=\"color: blue\">Function<\/span> GetGroupPageNumber(<span style=\"color: blue\">ByVal<\/span> group <span style=\"color: blue\">As<\/span> <span style=\"color: blue\">String<\/span>, _ <br \/>\n&nbsp;&nbsp;&nbsp; <span style=\"color: blue\">ByVal<\/span> pagenumber <span style=\"color: blue\">As<\/span> <span style=\"color: blue\">Integer<\/span>, <span style=\"color: blue\">ByVal<\/span> total <span style=\"color: blue\">As<\/span> <span style=\"color: blue\">Integer<\/span>, <span style=\"color: blue\">ByVal<\/span> filekey <span style=\"color: blue\">As<\/span> <span style=\"color: blue\">String<\/span>, _ <br \/>\n&nbsp;&nbsp;&nbsp; <span style=\"color: blue\">ByVal<\/span> preprocess <span style=\"color: blue\">As<\/span> <span style=\"color: blue\">Boolean<\/span>, <span style=\"color: blue\">ByVal<\/span> exporttype <span style=\"color: blue\">As<\/span> <span style=\"color: blue\">String<\/span>) <span style=\"color: blue\">As<\/span> <span style=\"color: blue\">Object<\/span> <br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style=\"color: blue\">Try<\/span> <br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style=\"color: blue\">If<\/span> pagenumber = 1 <span style=\"color: blue\">Then<\/span> <br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; groupNo = 0&nbsp;<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; currentgroup = <span style=\"color: #a31515\">&quot;&quot;<\/span> <br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; offset = 0 <br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style=\"color: blue\">If<\/span> exporttype = <span style=\"color: #a31515\">&quot;PDF&quot;<\/span> <span style=\"color: blue\">Then<\/span> <br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PDFRunCount += 1 <br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style=\"color: blue\">End<\/span> <span style=\"color: blue\">If<\/span> <br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style=\"color: blue\">End<\/span> <span style=\"color: blue\">If<\/span> <br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style=\"color: blue\">If<\/span> <span style=\"color: blue\">Not<\/span> (group = currentgroup) <span style=\"color: blue\">AndAlso<\/span> PDFRunCount &lt;&gt; 1 <span style=\"color: blue\">Then<\/span> <br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style=\"color: blue\">If<\/span> groupNo = 0 <span style=\"color: blue\">Then<\/span> <br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style=\"color: green\">&#39; fileName = System.IO.Path.GetTempPath() &amp; _<\/span> <br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; fileName = <span style=\"color: #a31515\">&quot;c:\\temp\\&quot;<\/span> &amp; _ <br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; filekey &amp; <span style=\"color: #a31515\">&quot;.xml&quot;<\/span> <span style=\"color: green\">&#39;System.IO.Path.DirectorySeparatorChar &amp;<\/span> <br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style=\"color: blue\">If<\/span> preprocess <span style=\"color: blue\">AndAlso<\/span> pagenumber = 1 <span style=\"color: blue\">Then<\/span> <br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sw = <span style=\"color: blue\">New<\/span> System.IO.StreamWriter(fileName, <span style=\"color: blue\">False<\/span>) <br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sw.WriteLine(<span style=\"color: #a31515\">&quot;&lt;root&gt;&quot;<\/span>) <br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sw.Close() <br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sw.Dispose() <br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sw = <span style=\"color: blue\">Nothing<\/span> <br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style=\"color: blue\">End<\/span> <span style=\"color: blue\">If<\/span> <br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style=\"color: blue\">ElseIf<\/span> preprocess <span style=\"color: blue\">Then<\/span> <br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sw = <span style=\"color: blue\">New<\/span> System.IO.StreamWriter(fileName, <span style=\"color: blue\">True<\/span>)&nbsp;<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sw.WriteLine( _<br \/>\n&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style=\"color: #a31515\">&quot;&lt;Group&nbsp; current=&#39;&quot;<\/span> &amp; currentgroup &amp;&nbsp; _<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style=\"color: #a31515\">&quot;&#39; lastPage=&#39;&quot;<\/span> &amp; <span style=\"color: blue\">CStr<\/span>(pagenumber &#8211; 1) &amp; <span style=\"color: #a31515\">&quot;&#39;\/&gt;&quot;<\/span>) <br \/>\n&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sw.Close() <br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sw.Dispose() <br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sw = <span style=\"color: blue\">Nothing<\/span> <br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style=\"color: blue\">End&nbsp;If<\/span> <br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; groupNo += 1 <br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; offset = pagenumber &#8211; 1 <br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; previousgroup = currentgroup <br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; currentgroup = group <br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style=\"color: blue\">End<\/span> <span style=\"color: blue\">If<\/span> <br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style=\"color: blue\">If<\/span> (pagenumber = total <span style=\"color: blue\">AndAlso<\/span> preprocess) <span style=\"color: blue\">Then<\/span>&nbsp;<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sw = <span style=\"color: blue\">New<\/span> System.IO.StreamWriter(fileName, <span style=\"color: blue\">True<\/span>) <br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sw.WriteLine( _<br \/>\n&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style=\"color: #a31515\">&quot;&lt;Group&nbsp; current=&#39;&quot;<\/span> &amp; currentgroup &amp; _<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style=\"color: #a31515\">&quot;&#39; lastPage=&#39;&quot;<\/span> &amp; <span style=\"color: blue\">CStr<\/span>(total) &amp; <span style=\"color: #a31515\">&quot;&#39;\/&gt;&quot;<\/span>)<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sw.WriteLine(<span style=\"color: #a31515\">&quot;&lt;\/root&gt;&quot;<\/span>) <br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sw.Close() <br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sw.Dispose() <br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sw = <span style=\"color: blue\">Nothing<\/span> <br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style=\"color: blue\">End<\/span> <span style=\"color: blue\">If<\/span> <br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style=\"color: blue\">Return<\/span> pagenumber &#8211; offset <br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style=\"color: blue\">Catch<\/span> Ex <span style=\"color: blue\">As<\/span> Exception <br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style=\"color: blue\">Return<\/span> Ex.Message() <br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style=\"color: blue\">End<\/span> <span style=\"color: blue\">Try<\/span> <br \/>\n&nbsp;&nbsp;&nbsp; <span style=\"color: blue\">End<\/span> <span style=\"color: blue\">Function<\/span>\n<\/p>\n<p>\nBesides creating the current page number for group as its result, the function creates an output file that looks like this:\n<\/p>\n<p class=\"code\">\n&lt;root&gt; <br \/>\n&nbsp;&nbsp; &lt;Group current=&quot;Central Africa&quot; lastPage=&quot;2&quot; \/&gt; <br \/>\n&nbsp;&nbsp; &lt;Group current=&quot;Eastern Africa&quot; lastPage=&quot;6&quot; \/&gt; <br \/>\n&nbsp;&nbsp; &lt;Group current=&quot;Northern Africa&quot; lastPage=&quot;7&quot; \/&gt; <br \/>\n&nbsp;&nbsp; &lt;Group current=&quot;Southern Africa&quot; lastPage=&quot;8&quot; \/&gt; <br \/>\n&nbsp;&nbsp; &lt;Group current=&quot;Western Africa&quot; lastPage=&quot;12&quot; \/&gt; <br \/>\n&nbsp;&nbsp; &lt;Group current=&quot;Eastern Asia&quot; lastPage=&quot;14&quot; \/&gt; <br \/>\n&nbsp;&nbsp; &lt;Group current=&quot;Middle East&quot; lastPage=&quot;16&quot; \/&gt; <br \/>\n&nbsp;&nbsp; &lt;!&#8211; etc &#8211;&gt; <br \/>\n&lt;\/root&gt;\n<\/p>\n<p class=\"NB\">\nBesides creating the current page number for group as its result, as you can see above, the function is also kind enough to tell you what went wrong by returning information about the error instead of a page number.&nbsp; That&#39;s why it returns Object instead of anything else.&nbsp; The report engine is kind enough, in return, to manage the cast for you.&nbsp; This is an invaluable practice; please take note for other hacky techniques no matter what you are doing.\n<\/p>\n<p>\nHere&#39;s the code for function #2.&nbsp; This one (very straightforward) only has to work during the second run.&nbsp; During the first run,&nbsp;as you can see from the report expression above, this function is not invoked, and the word &quot;[PreProcess Run]&quot; is displayed instead.&nbsp; You can see this in the report preview window, if you leave the PreProcess parameter value set at its default of <strong>true.<\/strong> <a href=\"\/lisa\/wp-non\/migrated\/PreviewPreProcessRun.png\" target=\"_blank\" rel=\"noopener\"><img loading=\"lazy\" decoding=\"async\" src=\"\/lisa\/wp-non\/migrated\/preview.png\" border=\"0\" alt=\"\" title=\"See what I'm talking \nabout?\" width=\"12\" height=\"12\" align=\"textTop\" \/><\/a>\n<\/p>\n<p class=\"code\">\n&nbsp;<span style=\"color: blue\">Function<\/span> ReadGroupPageTotal(<span style=\"color: blue\">ByVal<\/span> total) <span style=\"color: blue\">As<\/span> <span style=\"color: blue\">Object<\/span>&nbsp;<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp; <span style=\"color: blue\">Dim<\/span> g <span style=\"color: blue\">As<\/span> <span style=\"color: blue\">String<\/span>, xa <span style=\"color: blue\">As<\/span> System.Xml.XmlAttribute, thisLastPage <span style=\"color: blue\">As<\/span> <span style=\"color: blue\">Integer<\/span>&nbsp;<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp; <span style=\"color: blue\">Try<\/span>&nbsp;<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style=\"color: blue\">If<\/span> doc <span style=\"color: blue\">Is<\/span> <span style=\"color: blue\">Nothing<\/span> <span style=\"color: blue\">Then<\/span>&nbsp;<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; doc = <span style=\"color: blue\">New<\/span> System.Xml.XmlDocument()&nbsp;<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; doc.Load(fileName)&nbsp;<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style=\"color: blue\">End<\/span> <span style=\"color: blue\">If<\/span>&nbsp;<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style=\"color: blue\">If<\/span> doc <span style=\"color: blue\">Is<\/span> <span style=\"color: blue\">Nothing<\/span> <span style=\"color: blue\">Then<\/span>&nbsp;<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; g = <span style=\"color: #a31515\">&quot;NO DATA&quot;<\/span>&nbsp;<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style=\"color: blue\">Else<\/span>&nbsp;<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; xa = doc.SelectSingleNode( _<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style=\"color: #a31515\">&quot;\/root\/Group[@current=&#39;&quot;<\/span> &amp; currentgroup &amp; <span style=\"color: #a31515\">&quot;&#39;]\/@lastPage&quot;<\/span>)&nbsp;<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style=\"color: blue\">If<\/span> xa <span style=\"color: blue\">Is<\/span> <span style=\"color: blue\">Nothing<\/span> <span style=\"color: blue\">Then<\/span>&nbsp;<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; g = <span style=\"color: #a31515\">&quot;NO DATA&quot;<\/span>&nbsp;<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style=\"color: blue\">ElseIf<\/span> groupNo = 1 <span style=\"color: blue\">Then<\/span>&nbsp;<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; g = xa.Value&nbsp;<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style=\"color: blue\">Else<\/span>&nbsp;<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; thisLastPage = <span style=\"color: blue\">CInt<\/span>(xa.Value)&nbsp;<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; xa = doc.SelectSingleNode( _<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style=\"color: #a31515\">&quot;\/root\/Group[@current=&#39;&quot;<\/span> &amp; previousgroup &amp; <span style=\"color: #a31515\">&quot;&#39;]\/@lastPage&quot;<\/span>)&nbsp;<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style=\"color: blue\">If<\/span> xa <span style=\"color: blue\">Is<\/span> <span style=\"color: blue\">Nothing<\/span> <span style=\"color: blue\">Then<\/span>&nbsp;<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; g = <span style=\"color: #a31515\">&quot;NO DATA&quot;<\/span>&nbsp;<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style=\"color: blue\">Else<\/span>&nbsp;<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; g = (thisLastPage &#8211; <span style=\"color: blue\">CInt<\/span>(xa.Value))&nbsp;<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style=\"color: blue\">End<\/span> <span style=\"color: blue\">If<\/span>&nbsp;<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style=\"color: blue\">If<\/span> thisLastPage = total <span style=\"color: blue\">Then<\/span>&nbsp;<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; doc = <span style=\"color: blue\">Nothing<\/span>&nbsp;<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style=\"color: green\">&#39; could clean up file here<\/span>&nbsp;<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style=\"color: blue\">End<\/span> <span style=\"color: blue\">If<\/span>&nbsp;<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style=\"color: blue\">End<\/span> <span style=\"color: blue\">If<\/span>&nbsp;<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style=\"color: blue\">End<\/span> <span style=\"color: blue\">If<\/span>&nbsp;<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp; <span style=\"color: blue\">Catch<\/span> Exc <span style=\"color: blue\">As<\/span> Exception&nbsp;<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; g = <span style=\"color: #a31515\">&quot; error reading: &quot;<\/span> &amp; Exc.Message()&nbsp;<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp; <span style=\"color: blue\">End<\/span> <span style=\"color: blue\">Try<\/span>&nbsp;<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp; <span style=\"color: blue\">Return<\/span> g&nbsp;<br \/>\n<span style=\"color: blue\">End<\/span> <span style=\"color: blue\">Function<\/span>\n<\/p>\n<p>\nThis code is using System.Xml.&nbsp; Depending on your method of persistence,&nbsp;you may have to provide an explicit reference to the appropriate assembly or assemblies. You do this in the <strong>Report Properties<\/strong> dialog, <strong>References <\/strong>tab.&nbsp;&nbsp;I&#39;m using pretty basic functionality here,&nbsp;and I&nbsp;don&#39;t need to provide any class information in the dialog, just the assembly information. <a href=\"\/lisa\/wp-non\/migrated\/SystemXmlReferenceInRDLDialog.png\" target=\"_blank\" rel=\"noopener\"><img loading=\"lazy\" decoding=\"async\" src=\"\/lisa\/wp-non\/migrated\/preview.png\" border=\"0\" alt=\"\" title=\"See what I'm talking \nabout?\" width=\"12\" height=\"12\" align=\"textTop\" \/><\/a>\n<\/p>\n<h4>Now&nbsp;for the publishing<\/h4>\n<p>\nNow you just have to get this technique to work on the server.&nbsp; As explained earlier, you&#39;ll want to make sure you&#39;re writing to an &quot;acceptable&quot; location when you create your XML file or, if you&#39;re writing to a database, that you&#39;ve provided appropriate credentials for your connection.&nbsp; Other than that, deploying this report should be pretty&nbsp;much like deploying any other report you&#39;ve written&#8230; except for one thing.\n<\/p>\n<p>\nYou also have to make sure that your code has permissions to perform the requisite actions.&nbsp; This is one part that is definitely more sensible to do in a custom DLL, because you can add the permissions in a much more &quot;targeted&quot; way.&nbsp; Because I&#39;m doing this example completely in custom code, I need to issue a &quot;blanket&quot; permission for custom code in report expressions, I can&#39;t target it more accurately than that.\n<\/p>\n<p>\nTo do this, you have to change something in the rssrvpolicy.config file (you&#39;ll find it in your Reporting Services\\ReportServer webapp home directory).&nbsp; You&#39;ll find a code group that looks something like this:\n<\/p>\n<p class=\"code\">\n&lt;CodeGroup class=&quot;UnionCodeGroup&quot; version=&quot;1&quot; <br \/>\n&nbsp;&nbsp; PermissionSetName=&quot;Execution&quot; <br \/>\n&nbsp;&nbsp; Name=&quot;Report_Expressions_Default_Permissions&quot; <br \/>\n&nbsp;&nbsp; Description=<br \/>\n&nbsp;&nbsp; &quot;This code group grants default permissions for code in report expressions and Code element. &quot;&gt; <br \/>\n&nbsp; &#8230;\n<\/p>\n<p>\n&#8230; and, if you are following this walkthrough exactly as written, you&#39;ll need to change the PermissionSetName attribute value you see above from <strong>Execution<\/strong> to <strong>FullTrust<\/strong>.\n<\/p>\n<h4>Stay tuned.<\/h4>\n<p>\nThat&#39;s pretty much all she wrote.&nbsp; If you want to preview in Visual Studio or the Report Manager you can change the values of the parameters, making sure to keep them in synch: always call the preprocess run first and then the second run,&nbsp;make sure that you use the filekey to allow values to be maintained separately for different rendering systems and make sure that your preprocess+second run are <em>paired<\/em> for each rendering system.&nbsp; In other words, you can&#39;t preprocess for HTML and then call the second run for PDF; the page numbers won&#39;t be right.\n<\/p>\n<p>\nWhat does all this look on the client side, how do you get it to look seamless to the user?&nbsp; Not as hard as it sounds.&nbsp; I&#39;ll do that in a second installment of this walkthrough.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Another boring title for another important topic.&nbsp; When I wrote https:\/\/spacefold.com\/lisa\/2007\/09\/15\/Reset-On-Group-(Page-X-of-XX-in-a-group-within-a-total-Y-of-YY-for-the-report)-SQL-Reporting-Services-Style-, as usual I thought that was the end of it.&nbsp; Well, not exactly.&nbsp; I thought I was finished writing about that technique, and that I was going to go on and write more about debugging techniques and other related subjects in RS.&nbsp; It&#39;s a<a class=\"more-link\" href=\"https:\/\/spacefold.com\/lisa\/2008\/03\/03\/report-preprocessing-sql-server-reporting-server-group-pagetotals-walkthrough-part-i-the-rdl-and-the-server\/\">Read more<\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[5,6],"tags":[],"class_list":["post-139","post","type-post","status-publish","format-standard","hentry","category-reporting","category-sql-server"],"_links":{"self":[{"href":"https:\/\/spacefold.com\/lisa\/wp-json\/wp\/v2\/posts\/139","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/spacefold.com\/lisa\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/spacefold.com\/lisa\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/spacefold.com\/lisa\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/spacefold.com\/lisa\/wp-json\/wp\/v2\/comments?post=139"}],"version-history":[{"count":0,"href":"https:\/\/spacefold.com\/lisa\/wp-json\/wp\/v2\/posts\/139\/revisions"}],"wp:attachment":[{"href":"https:\/\/spacefold.com\/lisa\/wp-json\/wp\/v2\/media?parent=139"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/spacefold.com\/lisa\/wp-json\/wp\/v2\/categories?post=139"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/spacefold.com\/lisa\/wp-json\/wp\/v2\/tags?post=139"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}