Ramblings of the Sleepy…

For an underpaid web architect and overplayed gamer… there is no such thing as sleep.

IQueryable Methods on ActiveReports ControlCollections

Posted by David on July 25, 2008

I’m currently working on a project with an extremely complex, multi-page report.  Unfortunately, a customer requirement was EXACT typography to the “Excel” report and there are hundreds (literally) of data points randomly on the page. 

There isn’t a good way to iterate through the results (it’s a very detailed grade card for elementary students) and still match the layout requirements.

So, I went about “drawing” it out—lots of Label controls, lines, boxes, and such.  To save myself a bit of time assigning DataFields, querying results, etc., I opted for a different kind of iteration—control iteration.

My schema was simple: q#i#, for the quarter and the primary data point of the report, the indicator Id.  Since my business object, a Report, was already assigned to the ActiveReport document, I could simply iterate away!

Unfortunately, if you try to determine if the detail.Controls (a ControlCollection) contains a control and it doesn’t exist—it doesn’t simply return null, it throws an exception.  In addition, the ControlCollection doesn’t have an Exists or a FindControl method.  So, you’re stuck catching exceptions.

foreach (var indicator in _indicators)

{

try

{

var indicatorHeader =

string.Format(“i{0}”, indicator.Id);

((Label)detail.Controls[indicatorHeader]).Text =

IsSpanish                                                                           

? indicator.SpanishText                                                                          : indicator.EnglishText;

}

catch (Exception)

{

continue;

}

}

Unfortunately, that destroys performance—especially with hundreds of iterations (of indicators).

There’s a way around this, at least in my opinion.  Instead of addressing the controls as part of the details.Controls ControlCollection, use a custom IQueryable collection.

Begin by adding a private variable to the report to hold the controls.  In my case, all of the controls I’ll be modifying are Label (of ARControl) controls.

private IQueryable<Label> _controls;

On my ReportStart (I’m sure I could use another method, but since these are static controls, that seemed a good place to start), dump all Label controls into a generic List object (because you cannot add into an IQueryable).

var controlList = new List<Label>();

foreach (var control in detail.Controls.OfType<Label>())

{

controlList.Add(control);

}

_controls = controlList.AsQueryable();

OR, if you want to get fancy and save a few objects:

_controls = detail.Controls.OfType<Label>().AsQueryable();

At this point, your _controls object has all of the standard LINQ goodness.  Our foreach now looks like:

foreach (var indicator in _indicators)

{

var indicatorHeader =

string.Format(“i{0}”, indicator.Id);

var indicatorControl =

_controls.SingleOrDefault(x => x.Name == indicatorHeader);

if (indicatorControl != null)

       {

              indicatorControl.Text = IsSpanish

? indicator.SpanishText

: indicator.EnglishText;

}

}

The entire block can be wrapped in a try/catch—rather than each “object check”.  The report also runs almost 100x faster.

2 Responses to “IQueryable Methods on ActiveReports ControlCollections”

  1. Scott Willeke of Data Dynamics posted a response that might be helpful in your scenario. You can read it here
    http://blog.scott.willeke.com/2008/07/performance-golden-hammer-linq.html

  2. David said

    @Issam-

    Thanks for the head’s up regarding Scott’s post. I responded back on his blog–he has some excellent performance points!

    I’ll write up a response in a new post later today after a bit more code testing.

Leave a Reply

XHTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <pre> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>