SQL Server reporting services is very powerful – level 200

What’s in a name?  SQL Server reporting services doesn’t install as part of SQL Server.  Rather, it is an ASP.NET package that installs on the web server.  There is also a piece that installs into VS.NET.  Once it’s installed, the developer creates a new report project and chooses either a wizard or the designer.  Immediately, I realized that Microsoft had taken the powerful features in Access reports and made a .NET tool.  Reporting Services installs a powerful drag+drop designer for reports in VS.NET.  All you have to do is build your connection string and query, and then design the layout of the report.  There is also a Deploy menu option that will automatically deploy a report to the web server with reporting services installed.  Next, you give management the URL to the report, and they view it in a browser.  Fast, powerful and pretty.  Some other built-int features that will make business users drool:  Export to Excel and other formats.  At the top of every report is a combo box where the viewer can export this report to a file.  I noticed PDF was even on the list.

Kudos to Microsoft for re-releasing Access’s powerful report designer!  I installed the whole package and had an actual report deployed in an hour.

Binding to custom objects – level 200

First of all, I rated this post as 200 instead of 300 because I believe that intermediate-level ASP.NET developers SHOULD know about and be using the following technique. When learning data-binding techniques, we see all the samples either bind a single value or bind a DataSet to a grid. It’s very common to put data in a DataSet and bind it. I prefer to bind directly to a collection of custom objects. By creating a collection or array of custom objects (that contain the same data as the DataSet anyway) you benefit from being strongly-typed. You can bind to any property of your object that is a primitive type. For example, if you have:

public class Person
private int m_id;
public string FirstName;
public string LastName;
public int ID
get{ return m_id;}
public string FullName
get{ return FirstName + ” ” + LastName;}
public Person(int id, string firstName, string lastName)
m_id = id;
FirstName = firstName;
LastName = lastName;

you can assemble a collection or array of Person objects and then bind:

Person[] personList = new Person[5];
for(int i = 0; i < 5; i++)
personList[i] = new Person(1, “Jeffrey”, “Palermo”);

DataGrid1.DataSource = personList;

You can bind explicitly or let the grid auto-generate the columns.  You will notice that only the public properties of the Person class were auto-bound:  Even though we had two public fields, these were not automatically bound.  So the public properties are automatically bound.  I have taken advantage of this feature when binding objects that have custom objects as properties.  For instance, if one of the properties of the Person class was “Parent” of type Person, then I would create a property called ParentFullName, and that property would be bind-able.

Also, when binding to a DropDownList, you can write the following code:

myDDL.DataSource = personList;
myDDL.DataTextField = “FullName”;
myDDL.DataValueField = “ID”;

In this way, you can avoid creating a DataSet with the same data as that in your custom objects.  I prefer binding to object properties as opposed to a DataSet.  I think it makes the code more readable and maintainable.

Also, when I bind a list of objects to a DropDownList, I like to have a first entry that says “Select One”, or something similar.  So, after the DataBind() method, I explicitly add a first item:

myDDL.Items.Insert(0, new ListItem(. . .));

Then I have a first item before all the rest.

Finally, binding controls to custom objects is a very powerful feature of ASP.NET, and I think only binding to a DataSet is underusing this powerful feature.

Behavior of DataGrid.ItemDataBound and DataGrid.ItemCreated – level 200

When using the DataGrid control, one needs to know when to use the ItemDataBound event and when to use the ItemCreated event.  These event names are pretty easy to follow.  ItemCreated is when that row of the DataGrid is created.  The controls are there, but that’s it.  On the ItemDataBound event, the controls are bound to their data, an dthe data is available for access.  If you have logic that depends on the bound data, use the ItemDataBound event, which fires after the ItemCreated event.

In my dealings with using an embedded control in the DataGrid header, I need to access this control after it is created.  I can access this control in either event since this control doesn’t depend on data, so I elect to use the ItemDataBound event for this.  I have a button in my header, and I want to add a ServerClick event handler to it after it is created, so in the ItemDataBound event handler, I have to test the e.Item.ItemIndex.  The ItemDataBound event fires once for every row in the DataGrid.  The data-bound rows are 0-based, but for the header and footer, the ItemIndex is -1.  So if you have both the header and footer, then ItemIndex will be -1 twice.  For instance, to get the control in my header, I have to test for ItemIndex == -1, and then FindControl(”myButton”).  That will work for the header, but it will bomb later.  Why?

Because ItemDataBound is fired twice with ItemIndex == -1.  First for the header, then 0,1,2,3,4, etc for the data-bound rows, and then -1 again for the Footer.  Since myButton isn’t in the footer, I can’t find it.  Ok, so now I know that -1 in ItemDataBound happens twice.  Knowing this, I can code against it.

What I would rather see is DataGrid.Header.Controls and DataGrid.Footer.Controls since the Header and Footer are both controls within the DataGrid.  This would be a simpler API.

Just remember when embedding controls in your header or footer that the ItemIndex will be -1 when you access these controls in the ItemCreated or ItemDataBound event handlers.

Using embedded controls in the DataGrid control – level 300

When I first started developing with ASP.NET, I avoided the DataGrid control.  It seemed too confining, but that was because I didn’t fully understand it.  All the books and article I read gave DataGrid examples where you bind a data source and DataGrid takes over.  That’s not where it stops at all.  Now that I understand the DataGrid control, I realize that if I need bound tabular data, this is the control to use; however, I still find its defaults too confining.  I never use BoundColumns because rarely do I need just a plain textbox for data entry, so I always use TemplateColumns.  I can stick a DropDownList in there or anything else.  I know use embedded controls within the DataGrid very often, and I modify these controls through the DataGrid’s control tree.  On the ItemDataBound event, I can access controls in that row using:


but what about controls in the header or footer of the DataGrid?  I’m putting my “Add New” button in the header of the DataGrid as the column head of the column that has my edit, update, cancel, delete buttons, so the user can click on “Add New”, and a new editable row will appear.  Also, when I hide the DataGrid, this button will be hidden along with it.  So how do I programmatically find this control and use it? 

The DataGrid has no ID property for its Header, so I can’t explicitly access it, but looking at the control tree, I find that it is always the second control in the Controls collection when it’s visible.  I don’t know why it’s not the first, but it’s the second, and it gives it the ID of _ctl1.  So to access my button in my Header, I have to get Controls[1].FindControl(“myButton“).  This works, but I would like to set an ID to my Header so that I can find it explicitly.

Through understanding the DataGrid’s control tree and how it is structured, I’m able to modify any embedded control or add embedded controls on-the-fly.  Knowledge is power, and the more I learn about the DataGrid, the more powerful it becomes.


Display bliss – level 000

I’m sure some of you have a matrix of LCD flatscreens for your development display, but I work for a company that doesn’t think that’s a justafiable cost, so I’ve been using a 19” CRT with my Lattitude Laptop screen next to it as a second display.  Recently a co-worker quit and left behind a 21” monitor.  I snagged it and replaced my 19” with that, and I can really tell a different in readable screen real estate.  I’ve been using a 19” since 1998, so I notice the extra room immediately.

Noah Coad has LOST his C# MVP status!!!! – level 000

My friend and colleague, Noah Coad, is now a Microsoft employee (and cannot be that as well as an MVP).  We first met while working on a web project together in college at Texas A&M University.  I was Information Systems, and he was Computer Science.  He’s the best .Net developer I know personally, and I congratulate him on his new job as a Program Manager with VS Team System.  I look forward to using the IDE that he will help develop.