{"id":130,"date":"2008-05-25T15:21:00","date_gmt":"2008-05-25T15:21:00","guid":{"rendered":"\/lisa\/post\/2008\/05\/25\/Walkthrough-A-Simple-ish-Runtime-Quick-Report.aspx"},"modified":"2008-05-25T15:21:00","modified_gmt":"2008-05-25T15:21:00","slug":"walkthrough-a-simple-ish-runtime-quick-report","status":"publish","type":"post","link":"https:\/\/spacefold.com\/lisa\/2008\/05\/25\/walkthrough-a-simple-ish-runtime-quick-report\/","title":{"rendered":"Walkthrough: A Simple-ish Runtime Quick Report"},"content":{"rendered":"<p>\nSubtitle for this post probably should be: <strong>Yet More Fun with Report Parameters<\/strong>, or <strong>Sometimes the magic needs a little help<\/strong>.\n<\/p>\n<p>\n<a href=\"mailto:vijudei@gmail.com\" target=\"_blank\" title=\"Ask him yourself\" rel=\"noopener\">Vij<\/a> wrote in response to one of my <a href=\"\/lisa\/2007\/09\/19\/Dynamically-loading-reports-in-ReportViewers\/\" target=\"_blank\" title=\"Blog post on dynamic reporting\" rel=\"noopener\">dynamic reporting posts<\/a>:\n<\/p>\n<blockquote>\n<p>\n\tHi Lisa, I need help in creating columns dynamically in report viewer, but i have created RDLC statically. I am reading the data from XML file and only at run time I will be knowing columns count. Please guide me in this. I am working on C#. Thanks in advance, Vij\n\t<\/p>\n<\/blockquote>\n<p>\nThis is one of those things you can do a whole lot of different ways.&nbsp; I&#39;m going to show you one, with a few suggestions for variants.&nbsp;\n<\/p>\n<h4>Before we begin<\/h4>\n<p>\nUse the method you see here to get, well, a <em>quick<\/em> report.\n<\/p>\n<p>\nThis method is designed to take care of unknown data contents. To be that generic, you have to give up some frills.&nbsp; Because we don&#39;t know the contents of the columns being delivered, we&#39;re not going to know how wide to make each column, or much of anything else, such as formatting instructions.&nbsp; We&#39;ll make some slight exceptions for personalizing column headers, as you&#39;ll see.&nbsp;\n<\/p>\n<p class=\"NB\">\nHere&#39;s a thought for you: the generic nature of our Table control&#39;s display of columns will be simlar to what you see the output of a Matrix control &#8212; because that control has exactly the same problem-to-solve.\n<\/p>\n<p>\nI&#39;ll end this discussion with some thoughts about times when you want finer control.\n<\/p>\n<h4>Ready?<\/h4>\n<p>\nI don&#39;t know anything about Vij&#39;s XML file, and I don&#39;t know how much&nbsp;Vij knows at runtime before receiving the file.&nbsp;\n<\/p>\n<p>\nI&#39;m going to assume only that he can stipulate&nbsp;a maximum number of columns possible for his data, or at least a maximum number of columns that will be allowed to show in the report.&nbsp; This makes sense for pagination reasons, in any type of generic report.\n<\/p>\n<p>\nAlso, because Vij says &quot;I am working on C#&quot; I am going to use as little report code as possible (although I don&#39;t see what difference it can possibly make that the trivial embedded report code will be in VB).\n<\/p>\n<p>\n&nbsp;\n<\/p>\n<h4>1. Start with a&nbsp;parameter<\/h4>\n<p>\nSteve Martin used to have a routine about being a millionaire&#8230; without ever paying taxes.&nbsp; &quot;First,&quot; he would say, &quot;get a million dollars&quot;.&nbsp; Luckily our first step is easier to accomplish.&nbsp;\n<\/p>\n<p>\nWe&#39;ll add a single parameter of String type, called <strong>WhichColsUnknown<\/strong>, for no particular reason, except I&#39;d like to distinguish it from a second scenario in which the columns are determined at runtime but you know the full set of possible columns from the beginning.&nbsp; In any case, million dollars or no,&nbsp;our&nbsp;single&nbsp;parameter will buy us a lot.\n<\/p>\n<p>\nWe&#39;ll use this parameter to pass a comma-delimited list of the field names that should be displayed.&nbsp; In this scenario, because Vij is using an RDLC (a local report), he has control of the dataset before he runs the report.&nbsp; He can check the dataset and build this comma-delimited list of whatever field names happen to be present in it.&nbsp;\n<\/p>\n<p class=\"NB\">\nIf you&#39;re playing along at home, just make the SQL Command for your dataset <strong>SELECT * FROM &lt;some table&gt;<\/strong>, expose the parameter, and type in a delimited list of field names at will, in the parameter value, to test the premise. Don&#39;t put any extra spaces in your delimited list of field names, or add trimming statements to the expressions you see here.&nbsp; And don&#39;t worry; if you&#39;re working with the data on a Report Server rather than an RDLC,&nbsp;everything here still applies.&nbsp;&nbsp;\n<\/p>\n<h4>2. Add some generic behavior<\/h4>\n<p>\nNow you need to tell the report how many columns are present in this report run.&nbsp; Well, strictly speaking, as you&#39;ll probably be able to figure out from the next steps in this walkthrough, you don&#39;t <strong>need<\/strong> to do this.&nbsp; You could make the determination on each expression.&nbsp; It&#39;s just more efficient to do it once.\n<\/p>\n<p>\nI&#39;ll use a variable to do that, called HowMany.&nbsp; You can make HowMany a second parameter and pass the&nbsp;value if you wish, but I think it will be easier to make the method consistent between RDLs and RDLCs if you embed this behavior in the report.&nbsp; &nbsp;\n<\/p>\n<p>\nWe&#39;ll initialize this variable, in the Page Header. If for some reason you don&#39;t have any existing content in the page header, you can use an expression such as the following in a very <strong>tiny<\/strong> Page Header (the expression returns &quot;&quot;):\n<\/p>\n<p class=\"code\">\n=Code.InitializeColCount(Parameters)\n<\/p>\n<p>\nAssuming you&nbsp;have content in your Page Header, just attach the expression you see above to any textbox, like this:\n<\/p>\n<p class=\"code\">\n=Code.InitializeColCount(Parameters)<br \/>\n&nbsp; &nbsp;&amp; &quot;My Real Report Header&quot;&nbsp;\n<\/p>\n<p>\nHere&#39;s what the code looks like to match what you see above:\n<\/p>\n<p class=\"code\">\nPublic HowMany As Integer =0 <\/p>\n<p>Function InitializeColCount(p AS Parameters) AS String<br \/>\n&nbsp;&nbsp; If HowMany = 0 Then<br \/>\n&nbsp;&nbsp; &nbsp; &#39; initialize only once<br \/>\n&nbsp;&nbsp; &nbsp; HowMany = p(&quot;WhichColsUnknown&quot;).Value.Split(&quot;,&quot;).Length<br \/>\n&nbsp;&nbsp; End If<br \/>\n&nbsp;&nbsp; Return &quot;&quot;<br \/>\nEnd Function\n<\/p>\n<p>\n&#8230; not too much of a VB burden to impose, is it? &lt;g&gt;\n<\/p>\n<h4>&nbsp;&nbsp;<\/h4>\n<h4>3. Hide the extra columns<\/h4>\n<p>\nAdd your stipulated &quot;maximum number of columns&quot; to this report, in a table with whatever formatting you want.&nbsp; And, now, as you&#39;ve probably guessed, &nbsp;you need to use Visibility to determine how many columns should show in the report, using this variable.\n<\/p>\n<p>\nBeing careful to put the attribute on the <strong>column<em> <\/em><\/strong>level &#8212; not on a textbox &#8212; use expressions like the following on each column (this one is for column #3):\n<\/p>\n<p class=\"code\">\n=Code.HowMany &lt; 3\n<\/p>\n<p>\nBut what should you actually put <strong>in<\/strong> each column, as expressions?&nbsp; I&#39;ll show you a basic version and then we&#39;ll probably iterate a bit.\n<\/p>\n<h4>&nbsp;&nbsp;<\/h4>\n<h4>4. Add generic expressions to show column headers and column content<\/h4>\n<p>\nRemember: our parameter has the instructions providing field names.&nbsp; So each column shows the contents of the appropriate field using an expression similar to the following.&nbsp; This one is, again, for column #3 (remember the Fields collection is a 0-based array, so we&#39;re one off).\n<\/p>\n<p class=\"code\">\n=Fields(<br \/>\n&nbsp;&nbsp; Parameters!WhichColsUnknown.Value.Split(&quot;,&quot;)(2)).Value\n<\/p>\n<p class=\"NB\">\nYes it&#39;s a bit&nbsp;tedious to put in all these expressions by hand with the index change on each entry.&nbsp; You can make it less tedious a couple of ways, such as pasting them all in and then editing them in the XML directly, in my case.&nbsp; Or maybe you would prefer a hidden parameter that ties textbox names to index values, and you&#39;ll write a function to figure out what index belongs to each column.&nbsp; Go ahead&#8230;\n<\/p>\n<p>\nWe can use a similar expression in our most &quot;basic&quot; version of this report to dump the field name in as the column header for each column (again this example shows the correct expression for column #3)\n<\/p>\n<p class=\"code\">\n=Parameters!WhichColsUnknown.Value.Split(&quot;,&quot;)(2)\n<\/p>\n<h4>&nbsp;&nbsp;<\/h4>\n<h4>5. You&#39;re basically done.&nbsp; Want fancier column headers?<\/h4>\n<p>\nWe could also add just a little more code to make a smarter determination of what our column headers should look like.&nbsp; Instead of the last expression above, write something like this into each column header (still using column #3 as an example):\n<\/p>\n<p class=\"code\">\n=Code.GetColHeader(2, Parameters )\n<\/p>\n<p>\nYou can probably imagine the code that goes into this function:\n<\/p>\n<p class=\"code\">\nFunction GetColHeader(index AS Integer, p As Parameters) AS String<br \/>\n&nbsp;&nbsp; Dim h As String = &quot;&quot;<br \/>\n&nbsp;&nbsp; If HowMany &gt;= index + 1 Then<br \/>\n&nbsp;&nbsp; &nbsp;&nbsp; h =&nbsp; p(&quot;WhichColsUnknown&quot;).Value.Split(&quot;,&quot;)(index)<br \/>\n<span style=\"color: #008000\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &#39; do more work here<\/span><br \/>\n&nbsp;&nbsp; End If<br \/>\n&nbsp;&nbsp; Return h<br \/>\nEnd Function\n<\/p>\n<p>\nWhere it says <span style=\"color: #008000\">&#39;do more work here<\/span>, you might (for example) replace underscores with spaces, change casing, or&nbsp;reference&nbsp;a second parameter holding your preferred column header labels in the same order.&nbsp; Whatever you&#39;d like.\n<\/p>\n<p>\nI&#39;m not going to belabor this idea, especially not the &quot;second parameter&quot; one, because I&#39;d like to offer an alternative: if you&#39;re going to bring information in from the &quot;outside world&quot; via&nbsp;a parameter regarding custom column labels, you might prefer to do it as a second dataset you attach to the report, with the same number of columns as your maximum number of columns.&nbsp; That dataset might look something like the following (in a case where 8 is my maximum number of columns and I have a primary data set with 6 columns available on this run):\n<\/p>\n<p class=\"code\">\nSELECT &#39;Sales Number&#39; AS Field1, <br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &#39;SalesPerson&#39; AS Field2,&nbsp;<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#39;Order Type&#39; AS&nbsp; Field3,<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &#39;Qty&#39; AS&nbsp; Field4, <br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &#39;Customer&#39; AS&nbsp; Field5,<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &#39;Active&#39; AS&nbsp; Field6,<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SPACE(0) AS Field7,<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SPACE(0) AS Field8\n<\/p>\n<p>\nNow my column header expression for the column #3 looks like this (where &quot;ColHeaders&quot; is the name of my extra dataset):\n<\/p>\n<p class=\"code\">\n=First(Fields(&quot;Field3&quot;).Value, &quot;ColHeaders&quot;)\n<\/p>\n<h4>&nbsp;&nbsp;<\/h4>\n<h4>6. What&nbsp;can I improve if&nbsp;I <em>do <\/em>know all about the full set of possible columns?<\/h4>\n<p>\nSometimes you might have more control over the dataset &#8212; you know the full set, but not which ones are being delivered, or which ones a certain requestor is allowed to see, or in what order they should be displayed, until runtime.&nbsp;\n<\/p>\n<p>\nIn that case, you can use a simpler version of this technique, with a multi-valued parameter that provides both field names (as its &quot;values&quot;) and column headers (as its &quot;labels&quot;).&nbsp; This is the second scenario I mentioned earlier; let&#39;s call this multi-valued parameter <strong>WhichCols<\/strong>.\n<\/p>\n<p>\nYour column visibiity expression for column #3 now looks like this:\n<\/p>\n<p class=\"code\">\n=Parameters!WhichCols.Value.Length &lt; 3\n<\/p>\n<p>\n&#8230; the column header expression for column #3 now looks like this:\n<\/p>\n<p class=\"code\">\n=Parameters!WhichCols.Label(2)\n<\/p>\n<p>\n&#8230; and the expression to show the data in column #3 now looks like this:\n<\/p>\n<p class=\"code\">\n=Fields(Parameters!WhichCols.Value(2)).Value\n<\/p>\n<h4>&nbsp;&nbsp;<\/h4>\n<h4>7. What if I want more &quot;tuned&quot; formatting for each column?<\/h4>\n<p>\nA generic report basically provides good value for money.\n<\/p>\n<p>\nIf you want finer control over the behavior of each column, you can adapt what you see here somewhat, by providing different sets of columns with different widths and a bit more metadata instructions about how to treat each field in the dataset, using similar techniques to what you see above.&nbsp;Have some columns &quot;suitable to currency display&quot;, some for &quot;long text display&quot;, etc. &nbsp;Then you can assign your data columns to the table columns that are &quot;most like&quot; the expected contents.&nbsp;\n<\/p>\n<p>\nBut really, my friend, IMHO this is where you should get off this particular bus and accept a transfer pass to a different route: adjusting the&nbsp;report definition dynamically at runtime.&nbsp;\n<\/p>\n<p>\nYou can even create&nbsp;the full RDL or RDLC&nbsp;from scratch if you want &#8212; you&#39;ll find instructions on <a href=\"http:\/\/gotreportviewer.com\/\">http:\/\/gotreportviewer.com\/<\/a>.\n<\/p>\n<p>\nAlternatively, keep a couple of dummy&nbsp;report definitions around, again holding column definitions &quot;suitable for&quot; different types of data.&nbsp; Add and subtract those columns directly into a template report definition, as&nbsp;appropriate for your current data set, before running the report.&nbsp;\n<\/p>\n<p>\nIt might not be a million dollars,&nbsp;but, effort-wise, you pays your money and you takes your choice. As <a href=\"http:\/\/en.wikipedia.org\/wiki\/List_of_minor_characters_in_Firefly#Mr._Universe\" target=\"_blank\" title=\"Mr. Universe on Wikipedia\" rel=\"noopener\">Mr. Universe<\/a> would&nbsp;say, <em>That&#39;s my motto, or it might be if I start having a motto.<\/em><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Subtitle for this post probably should be: Yet More Fun with Report Parameters, or Sometimes the magic needs a little help. Vij wrote in response to one of my dynamic reporting posts: Hi Lisa, I need help in creating columns dynamically in report viewer, but i have created RDLC statically. I am reading the data<a class=\"more-link\" href=\"https:\/\/spacefold.com\/lisa\/2008\/05\/25\/walkthrough-a-simple-ish-runtime-quick-report\/\">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-130","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\/130","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=130"}],"version-history":[{"count":0,"href":"https:\/\/spacefold.com\/lisa\/wp-json\/wp\/v2\/posts\/130\/revisions"}],"wp:attachment":[{"href":"https:\/\/spacefold.com\/lisa\/wp-json\/wp\/v2\/media?parent=130"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/spacefold.com\/lisa\/wp-json\/wp\/v2\/categories?post=130"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/spacefold.com\/lisa\/wp-json\/wp\/v2\/tags?post=130"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}