The source code for this article can be downloaded here.
While there is no official Data Grid in Windows Presentation Foundation (WPF) you can still layout your data quite easily using the Grid Panel. In WPF/E (E for Everywhere) there is no Grid Panel and you must lay everything out using a Canvas where you must specify the absolute position of every item. WPF/E also has no method of data binding, so creating a data grid is not as simple as DataGrid.DataBind().
In this article I will demonstrate how to simulate both a grid layout and data binding in WPF/E. This will be the first article in the series and will only show the basics with later articles taking this approach even further. Before we get started you will need the following items:
- Northwind sample database - For this article you can host this in SQL Server 2005, SQL Server Express, or SQL Server 2000. However, future articles will make use of SQL Server 2005 features and the source code was coded against SQL Server 2005.
- WPF/E Feb CTP SDK - You will need the SDK and the aghost.js file from the SDK.
- ASP.Net AJAX 1.0 - I also reference the ASP.Net AJAX Futures CTP in the project, but for this article you only need the base 1.0 features.
- Enterprise Library for .NET Framework 2.0 - This makes our calls to SQL Server much simpler.
Setting Up The Database
The first step is to attach the database to the SQL Server. In SQL Server 2005 you need to open up the SQL Server Management Studio, right click Databases under your server, and select Attach. Browse the the MDF file that was extracted from the Northwind sample database installer. We will be using the Photo column of the Employees table for our images (yes, they are terrible images, but for a demo they will work). However, there are two problems with the data in the Photo column (1) it has a header that makes it so you can load it in .NET and (2) it is a GIF image which isn't supported by WPF/E. So to get around this issue I wrote a console application that strips off the first 78 bytes and then saves the image back as a JPEG (it is included in the source code). So you will need to run that application against your database to convert the images to the right format.
The process for doing this with SQL Express is probably a little different and I leave this as an exercise for the reader (of course you can just add your own images instead using the ones in the database).
The Website Project
Next we can turn our attention to the website project. The project is made up of the following items:
- Default.aspx - the only page in the site
- EmployeeService.asmx - the web service that we will be calling
- PhotoHandler.ashx - the IHTTPHandler that returns the images from the database
- Web.config - the configuration file for the website
- App_Code/Employee.cs - the Employee object
- App_Code/EmployeeData.cs - the Data Access Layer (DAL) for Employee data
- App_Code/EmployeeService.cs - the code behind for the web service
- scripts/aghost.js - The WPF/E aghost file from the Feb CTP (part of the SDK)
- scripts/grid.js - The javascript that we will use to build our grid
- xaml/grid.xaml - The xaml for our grid (not much there)
I'm not going to cover how the DAL works or what the photo http handler is doing since that is outside the scope of this article and they are fairly simple. We will start with taking a look at the Default.aspx page since that is where everything begins. There are three important things to look at in this page. First, you will notice that we reference both the aghost.js file and the grid.js file. Second, we have the ASP.Net AJAX script manager which we point to our EmployeeService web service url. This tells ASP.NET AJAX to build a javascript proxy for our webservice which we can call via javascript. This is how we will get our list of employees out of the database and into our WPF/E data grid. Third we have the script to create the WPF/E control which makes a call to the code in the aghost.js file. This will load up our grid.xaml which is what we will look at next.
Building the Data Grid
The base of our data grid is the grid.xaml file. If you open this file you will see that it is pretty much an empty canvas. The two important things for this file are the Loaded="javascript:loaded" and the x:Name="root". The Loaded event gets fired when the control has finished loading the canvas. This is important because this is what will trigger the building of the data grid. We give the canvas a name so that we can add the elements of our grid to it at run time.
The javascript loaded function is found in the grid.js file. This file is where the action happens. The loaded function is very basic in that it simply creates a new instance of the javascript grid object that is defined below it. I try to encapsulate all my javascript code in to objects since it helps keep the code neat and I find it smells better than a bunch of functions by themselves.
In the grid object's constructor we define three properties: the WPF/E control, the root canvas, and the item template. If you want to change how your data grid items look you can tweak the item template. After defining these items we make a call to EmployeeService.GetEmployees. This is the javascript proxy that was created for us by ASP.Net AJAX. It is an asynchronous call and we pass to it the method we want to be called when the service returns. In this case we want it to call the loadEmployees method of our grid object, but we really want it to call the method on the grid object that we are currently using. In order to do this we use the delegate object which I borrowed from the WPFEPad project (which BTW is a great project to dissect in order to learn about WPF/E and javascript).
When the call returns it calls our loadEmployees method where we will start the process of adding the employees to our data grid. At the top of the method are some variables which you can tweak to change the spacing and layout of our grid. Make sure the itemWidth is the same as the Width of the canvas in the template, otherwise things will overlap. The javascript proxy returns an array of Employee objects (as defined in the Employee.cs file) which we will loop through, apply to the template to create the Xaml for each Employee, and then add back to the canvas with the appropriate Canvas.Top and Canvas.Left settings. Note that we reference the ActualWidth of the control to determine how much space we have to place the employees.
After we have added the employee xaml to the canvas, we find the name TextBlock (as defined by our template) and center it using the ActualWidth of the TextBlock. This is how you center text in WPF/E since there is currently no alignment property for TextBlocks.
Finally we check to see where we are to see if we need to start a new row of employees. If you run the example you should get something that looks like the following in your browser:
So you now have a very simple data grid created using WPF/E and ASP.Net AJAX.
Next Steps
At this point the grid is very simple so there are quite a few enhancements that we could add. Here are a few of the ones that I have in mind:
- Paging and Sorting
- Click Events that allow you to see the Employee details
- Mouseover effects
- Handle resizes and full screen
Another thing to keep in mind is that we could build a lot of this using an ASP.Net page that generates the Xaml and only use the javascript code to line the items up. This is another approach which I will leave as an exercise for you. :)
Technorati Tags: WPF/E