kick it on DotNetKicks.com   Shout it  

SQL Server Reporting Services (SSRS): Databinding with CustomReportItem implementation

For my current project, I've been attempting something that would seem simple to do, but can't be done in Sql Server Reporting Services (SSRS). I am trying to draw 2 simple rectangles on the grid of a scatter (XY) chart. The reason for doing this is to visually indicate good and bad regions of data. But when the report is rendered (at least using the Html viewer) the rectanges I draw above the chart have moved. This is because items cannot overlap in the web viewer.

I have come to find that I can create a CustomReportItem based on any image I can draw or retrieve (Gdi+ or any other method of creating an image like the file system or a remote url). So I started looking at the alternative charting options I had available to me through my client's software licenses.

My options were charting solutions by ComponentArts and Infragistics (UltraChart). As it stands the ComponentArts documentation was dismal and I am still waiting to hear back about a message I posted on their forum over a week ago. With Infragistics I found the documentation much better. When I needed help I got an immediate response.

So I am using Infragistics for my charting needs. The solution involves creating a custom report item which allows the user to define a set of properties which I then use to design the chart. I am actually using the Web version of UltraChart, which is not supported, but works well. I could have used the WinForms version, but it doesn't seem to make any difference and I didn't have it installed at the time I began my discovery.

The next problem I encountered was creating the CustomReportItem. Again, like the ComponentArts library, the documentation was pitiful. But here are the links I did find to nonetheless. This was difficult to track down :

Rdl definitions: http://download.microsoft.com/download/c/2/0/c2091a26-d7bf-4464-8535-dbc31fb45d3c/rdlNov05.pdf . When you are working on your designer class, this will make sure the xml output is correct (hint: pay attention to all the 1-N, 0-1, 1 designations to know what's required and what's optional).

Custom Report Item docs: http://msdn2.microsoft.com/en-us/library/ms345224.aspx . For whatever reason I didn't find this when I first started searching. It never came up in google. I found it later when I was looking for information on a specific class.

MSDN Magazine: http://msdn2.microsoft.com/en-us/magazine/cc188686.aspx . A pretty good learning example, but didn't have everything I need. Also, there was no direct link to the source code. You have to download the source for the entire issue and extract it locally. The source can be found here: http://download.microsoft.com/download/f/2/7/f279e71e-efb0-4155-873d-5554a0608523/MSDNMag2006_10.exe

A data bound example of drawing polygons by Chris Hays: http://blogs.msdn.com/chrishays/archive/2005/10/04/CustomReportItemSample.aspx . The code was difficult to follow and there weren't many comments. This didn't help me until the end when I understood more of what was going on. Also, you have to register with the group before you can download the code.

The last problem I had to solve was how to bind a dataset to my custom report item. The only thing that really helped me here was the Rdl documentation. The problem was that the code which was relevant to performing this operation was uncommented and wasn't explained anywhere in the documentation or samples. So here's my own databinding snippets with comments and explaination.

A) In the CustomReportItemDesigner class (your custom class which inherits from it as a base), override the InitializeNewComponent() method like this:




public override void InitializeNewComponent()
{
base.InitializeNewComponent();

CustomData = new CustomData();

//at least one grouping is required for both rows and columns

//initialize row grouping
CustomData.DataRowGroupings = new DataRowGroupings();
CustomData.DataRowGroupings.DataGroupings = new List<DataGrouping>(1);
CustomData.DataRowGroupings.DataGroupings.Add(new DataGrouping());
CustomData.DataRowGroupings.DataGroupings[0].Grouping = new Grouping();
CustomData.DataRowGroupings.DataGroupings[0].Grouping.Name = Name + "_Row";
CustomData.DataRowGroupings.DataGroupings[0].Grouping.GroupExpressions = new GroupExpressions();
CustomData.DataRowGroupings.DataGroupings[0].Grouping.GroupExpressions.Add(new Expression());

// initialize a Static column grouping
CustomData.DataColumnGroupings = new DataColumnGroupings();
CustomData.DataColumnGroupings.DataGroupings = new List<DataGrouping>(1);
CustomData.DataColumnGroupings.DataGroupings.Add(new DataGrouping());
CustomData.DataColumnGroupings.DataGroupings[0].Static = true;

//initialize data row with empty values for designer
CustomData.DataRows = new List<DataRow>(1);
CustomData.DataRows.Add(new DataRow());
CustomData.DataRows[0].Add(new DataCell());

//define the fields you will store (these will be populated with expressions by custom designer properties you define)
CustomData.DataRows[0][0].Add(new DataValue("X", String.Empty));
CustomData.DataRows[0][0].Add(new DataValue("Y", String.Empty));
}

B) Define a custom designer property to set the expression for your data row group.

        [Browsable(true), Category("Data")]
public string LabelValue
{
get
{
if (CustomData.DataRowGroupings.DataGroupings.Count > 0)
{
return GetGroupLabel(CustomData.DataRowGroupings.DataGroupings[0].Grouping);
}
else
return "Point Label";
}
set
{
CustomData.DataRowGroupings.DataGroupings[0].Grouping.GroupExpressions[0].String = value;
}
}

private string GetGroupLabel(Grouping group)
{
if (group.GroupExpressions != null && group.GroupExpressions.Count > 0)
return group.GroupExpressions[0].String;

return null;
}

C) Define custom designer properties to set the expressions for the DataValuesCollection (only showing one property here to keep things shorter)

public string XValue
{
get
{
if (CustomData.DataRows.Count > 0 && CustomData.DataRows[0].Count > 0)
return GetDataValue(CustomData.DataRows[0][0], "X");
else
return "X Coordinate";
}
set
{
SetDataValue(CustomData.DataRows[0][0], "X", value);
}
}


private string GetDataValue(DataCell cell, string name)
{
foreach (DataValue value in cell)
if (value.Name == name)
return value.Value;
return null;
}

private void SetDataValue(DataCell cell, string name, string expression)
{
foreach (DataValue value in cell)
if (value.Name == name)
{
value.Value = expression;
return;
}
DataValue datavalue = new DataValue(name, expression);
cell.Add(datavalue);
}

D) Make sure your designer provides a property to set the data set name (CustomData.DataSetName).

E) Your CustomReportItem class can then read the data like this:


private void ReadCustomData()
{
DataMemberCollection members = m_CRI.CustomData.DataRowGroupings[0];
DataCellCollection rows = m_CRI.CustomData.DataCells;

//get the position of each field in the data value collection
int xpos = -1, ypos = -1;

for (int field = 0; field < rows[0, 0].DataValues.Count; field++)
{
switch (rows[0, 0].DataValues[field].Name)
{
case "X":
xpos = field;
break;
case "Y":
ypos = field;
break;
}
}

//populate the series for the chart data
for (int row = 0; row < rows.RowCount; row++)
{
DataValueCollection values = rows[row, 0].DataValues;

String label = members[row].GroupValues[0].ToString();

double x = Convert.ToDouble(values[xpos].Value);
double y = Convert.ToDouble(values[ypos].Value);
}
}

I haven't posted the full code here but I plan on doing so in the future. I also plan on dressing this post up and making a codeproject article out of it.

Tags: , ,

kick it on DotNetKicks.com   Shout it  

Feedback

# 

Gravatar Hi ,

In my current project, i need to implement a reporting service for ASP.NET applicaiton. We are not requiring a report designer utility to be used by the users of the system at runtime. Report designing is going to be considered as a customization activity. The reports will be designed and made available for the users. We are planning to use infragistic for our charting needs. I was thinking of creating a solution around Microsoft Reporting System. The report designer and viewer is readily available. All i have to do is create datasets, the data retrieval logic, and then tie it to the report and display it. But however i am still clueless of how to use Infragistics inside the RDLC reports. I could corelate my requirements to yours and have a feel that custom report item is the way to go forward. Let me know what you think?

Regards,
NInaad 5/12/2008 10:45 PM | noreply@blogger.com (Anonymous)

# 

Gravatar My first response would be why not use the built-in chart control from Infragistics for ASP.NET, UltraWebChart? It integrates nicely with ASP.NET web forms and allows much more control and user interaction.

My reason for integrating with SSRS was because the entire solution I was working on was already built on SSRS and there were specific features of SSRS that were expected to be available from all reports.

If I were starting a new app and knew I would need to use Infragistics I wouldn't have used SSRS. The reason is that CustomReportItem is so poorly documented. For example, if you decide you need to change the grouping databindings setup in the InitializeComponent method you're pretty much on your own because there is only one example of it out there.

Planning an entire solution around CustomReportItem will be a lot of work. If you must use SSRS and want more control than is given to you, look into Dundas or ComponentArt instead of Infragistics. The reason I chose Infragistics is because the client I did the work for owned copies of Infragistics and ComponentArt and Infragistics was the easier of the two to get the specific job done I needed.

I hope that helps you make a decision. 5/14/2008 8:35 AM | noreply@blogger.com (Mark J. Miller)

# 

Gravatar Keep up the good work. 11/10/2008 11:02 AM | noreply@blogger.com (Magdalena)

# re: SQL Server Reporting Services (SSRS): Databinding with CustomReportItem implementation

Gravatar SSRS has a lot of useful features for enterprise reporting. It is easier to create new reports and supports scheduled caching, snapshots and emails. All are very important features when you are dealing with huge data sources and millions of records.
If you use a plain web application then you'd have to architect and develop your in-house reporting services to include all the feature I mentioned above. It will be easy and fast to work with small sets of data, but when you start dealing with larger data sets (you inhouse app grows in few years), you'd have to implement some sort of timed/scheduled caching mechanism or you'll have to convince users to be accept a long running report >30 seconds are the worst.

It is a shame however that the SSRS charts are limited, NO HOVER EFFECT for example. 9/15/2009 8:32 AM | WeSam Abdallah

# re: SQL Server Reporting Services (SSRS): Databinding with CustomReportItem implementation

Gravatar WeSam, I am not attempting to dissuade anyone from using SSRS. You're right it is a very valuable solution. But the question was asked about integrating another charting engine with SSRS for an entire solution. My post was more in the vein of a one-off solution. There is a TON of work involved in creating a custom report item for SSRS and there is no support if you have problems. So if SSRS works for your needs it is great, and if there are only a few reports which require custom work then you're still good. But the commenter above you is referring to building the entire reporting solution around integrating infragistics into SSRS. Doing this on your own is what I am recommending against. 9/17/2009 2:31 PM | MarkJMiller

Post a comment





 

Please add 7 and 3 and type the answer here:

 

 

Copyright © Mark J. Miller