I haven't played too much with ASP.NET 3.5's new control yet - so I figured it was about time I did a little research and checked it out. Typically, I like to document my research by creating a small prototype application focused on a handful of the new features that I am investigating. I find building a reference application is helpful because it tends to drive out some of those nasty implementation details that somehow remain hidden if I just browse the documentation or read a reference book.
So for a recent research project, I decided I would look into the LinqDataSource's control and attributes to see if they could be used to help me build a grid that supports grouping. Below is the final screen shot for my reference application. The grid shows the rows in the Northwind Orders table - grouped by the customer that placed the order. The group of orders for each customer can be expanded/collapsed by clicking on the plus/minus icon (no postback required). Read on if you are interested in the details. If you download the code, make sure to update the connection string in the web.config to point to your Northwind database.
|
The LinqDataSource Control
Below is what about the LinqDataSource control. In a nutshell, the control is a nice way to leverage the Linq features in your web apps.
Creating the Northwind DataContext
The LinqDataSource requires a context object that represents the data source. For my scenario I want to access the rows in the Orders table of the Northwind database, so my first step was to use Visual Studio's designer tools to create the context object for my Northwind database. To do this I opened the 'Add New Item' dialog and selected the 'LINQ to SQL Classes' template. I named my template Northwind.dbml and clicked Add.
If you connect Visual Studio's Server Explorer to your database, it becomes really easy to create entities from your the tables in your database. So once the designer was opened for the Northwind.dbml file, I opened the Server Explorer (CTRL + ALT + S), navigated out to my local SQL Server where I have my Northwind database. I expanded the Tables node in the Northwind tree and dragged the Orders table onto the design surface.
Configuring the LinqDataSource
After the Northwind DataContext was setup, I next moved on to configuring my LinqDataSource that I am using to fill the grid. I want to display all of the orders grouped by the customer that placed the order. To help me accomplish this, I configured the LinqDataSource as follows
The ContextTypeName points to the Northwind DataContext object that I created in the previous step and the TableName attribute is set to the table within the DataContext that I want to be fetching records from - Orders for this sample. The and attributes is where it gets a little more interesting. Like I mentioned earlier, I was to group the orders by the customer that placed the order. So I set the GroupBy attribute to the customerid column. If you look again at the screen shot for my grid, I am also displaying the customerid and the number of orders in the group using the following format: '{0} ({1} Orders)' where {0} is the customerid and {1} is the number of orders they placed. I want to use these values in my databinding expressions so I need to make sure to use them in the select statement. You can reference the grouped by property in the select statement by using the well known Key property. So when the orders for ALFKI are bound to the grid, Eval('Key') resolves to 'ALFKI' and Eval('Count') resolves to '6'.
The other interesting item in my Select statement is the use of the It keyword. The It keyword provides you with access to the individual items of the group - so in this scenario the orders for the individual groups. So for customer ALFKI, here are the values of the Key, Count and Items properties.
Key | Count | Items |
ALFKI | 6 | Order { ID='10643', OrderedDate='08/25/1997' ... } Order { ID='10692', OrderedDate='10/31/1997' ... } Order { ID='10702', OrderedDate='11/24/1997' ... } Order { ID='10835', OrderedDate='02/12/1998' ... } Order { ID='10952', OrderedDate='04/27/1998' ... } Order { ID='11011', OrderedDate='05/07/1998' ... } |
Configuring the ListView
After my LinqDataSource was all setup I started working on creating the and its data binding expressions that are used to fill my grid. I thought the easiest way to produce the markup for the grouping was to use two ListView's, one nested inside the other. The outer ListView is responsible for rendering the grouping header rows and the nested ListView renders the orders belonging to each of the groups.
So I first created the outer ListView as follows. I set the DataSourceID to point to the LinqDataSource we configured in the previous section. Then I used the to define the header columns of the table and the to render the header rows for each of the groups. As you can see, I am referencing the Key and Count properties of the LinqDataSource using the standard DataBinding syntax.
Next, I added a nested ListView to the outer ListView for rendering the individual orders. For the nested ListView, I bound the DataSource property to the Items property of the LinqDataSource and I used regular DataBinding expressions to reference the individual properties of each of the orders.
Expanding and Collapsing the Groups
Finally, to put the finishing touches on the grid, I need a way to expand/collapse the groups by clicking on the plus/minus icon. To do this, I added a JavaScript function to the page called toggleGroup. This function applies and removes a css class called hidden the rows to control their visibility.
When the grid first renders, the hidden class is applied to all of the data rows. When the user clicks the plus icon, the following bit of JavaScript is run and uses the addCssClass/removeCssClass ASP.NET AJAX functions to add or remove the hidden class from the rows. Finally, the function takes care of updating the plus/minus icon.
That's it. Enjoy!