Home > .net 2.0, .net 3.0, .net 3.5, c#, LINQ, Visual Studio 2005, Visual Studio 2008 > IQueryable Methods on ActiveReports ControlCollections

IQueryable Methods on ActiveReports ControlCollections

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.

  1. July 27, 2008 at 3:15 pm

    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. July 28, 2008 at 9:19 am

    @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.

  1. No trackbacks yet.
Comments are closed.
%d bloggers like this: