WPF ListView as a DataGrid – Part 2
Posted
by psheriff
on ASP.net Weblogs
See other posts from ASP.net Weblogs
or by psheriff
Published on Mon, 29 Mar 2010 15:04:00 GMT
Indexed on
2010/03/29
15:13 UTC
Read the original article
Hit count: 944
In my last blog post I showed you how to create GridViewColumn objects on the fly from the meta-data in a DataTable. By doing this you can create columns for a ListView at runtime instead of having to pre-define each ListView for each different DataTable. Well, many of us use collections of our classes and it would be nice to be able to do the same thing for our collection classes as well. This blog post will show you one approach for using collection classes as the source of the data for your ListView.
Figure 1: A List of Data using a ListView
Load Property Names
You could use reflection to gather the property names in your class, however there are two things wrong with this approach. First, reflection is too slow, and second you may not want to display all your properties from your class in the ListView.
Instead of reflection you could just create your own custom collection class of PropertyHeader objects. Each PropertyHeader object will contain a property name and a header text value at a minimum. You could add a width property if you wanted as well. All you need to do is to create a collection of property header objects where each object represents one column in your ListView. Below is a simple example:
PropertyHeaders coll = new PropertyHeaders();
coll.Add(new PropertyHeader("ProductId", "Product ID"));
coll.Add(new PropertyHeader("ProductName", "Product Name"));
coll.Add(new PropertyHeader("Price", "Price"));
Once you have this collection created, you could pass this collection to a method that would create the GridViewColumn objects based on the information in this collection. Below is the full code for the PropertyHeader class. Besides the PropertyName and Header properties, there is a constructor that will allow you to set both properties when the object is created.
C#
public class PropertyHeader
{
public PropertyHeader()
{
}
public PropertyHeader(string propertyName, string headerText)
{
PropertyName = propertyName;
HeaderText = headerText;
}
public string PropertyName { get; set; }
public string HeaderText { get; set; }
}
VB.NET
Public Class PropertyHeader
Public Sub New()
End Sub
Public Sub New(ByVal propName As String, ByVal header As String)
PropertyName = propName
HeaderText = header
End Sub
Private mPropertyName As String
Private mHeaderText As String
Public Property PropertyName() As String
Get
Return mPropertyName
End Get
Set(ByVal value As String)
mPropertyName = value
End Set
End Property
Public Property HeaderText() As String
Get
Return mHeaderText
End Get
Set(ByVal value As String)
mHeaderText = value
End Set
End Property
End Class
You can use a Generic List class to create a collection of PropertyHeader objects as shown in the following code.
C#
public class PropertyHeaders : List<PropertyHeader>
{
}
VB.NET
Public Class PropertyHeaders
Inherits List(Of PropertyHeader)
End Class
Create Property Header Objects
You need to create a method somewhere that will create and return a collection of PropertyHeader objects that will represent the columns you wish to add to your ListView prior to binding your collection class to that ListView. Below is a sample method called GetProperties that builds a list of PropertyHeader objects with properties and headers for a Product object.
C#
public PropertyHeaders GetProperties()
{
PropertyHeaders coll = new PropertyHeaders();
coll.Add(new PropertyHeader("ProductId", "Product ID"));
coll.Add(new PropertyHeader("ProductName", "Product Name"));
coll.Add(new PropertyHeader("Price", "Price"));
return coll;
}
VB.NET
Public Function GetProperties() As PropertyHeaders
Dim coll As New PropertyHeaders()
coll.Add(New PropertyHeader("ProductId", "Product ID"))
coll.Add(New PropertyHeader("ProductName", "Product Name"))
coll.Add(New PropertyHeader("Price", "Price"))
Return coll
End Function
WPFListViewCommon Class
Now that you have a collection of PropertyHeader objects you need a method that will create a GridView and a collection of GridViewColumn objects based on this PropertyHeader collection. Below is a static/Shared method that you might put into a class called WPFListViewCommon.
C#
public static GridView CreateGridViewColumns(
PropertyHeaders properties)
{
GridView gv;
GridViewColumn gvc;
// Create the GridView
gv = new GridView();
gv.AllowsColumnReorder = true;
// Create the GridView Columns
foreach (PropertyHeader item in properties)
{
gvc = new GridViewColumn();
gvc.DisplayMemberBinding = new Binding(item.PropertyName);
gvc.Header = item.HeaderText;
gvc.Width = Double.NaN;
gv.Columns.Add(gvc);
}
return gv;
}
VB.NET
Public Shared Function CreateGridViewColumns( _
ByVal properties As PropertyHeaders) As GridView
Dim gv As GridView
Dim gvc As GridViewColumn
' Create the GridView
gv = New GridView()
gv.AllowsColumnReorder = True
' Create the GridView Columns
For Each item As PropertyHeader In properties
gvc = New GridViewColumn()
gvc.DisplayMemberBinding = New Binding(item.PropertyName)
gvc.Header = item.HeaderText
gvc.Width = [Double].NaN
gv.Columns.Add(gvc)
Next
Return gv
End Function
Build the Product Screen
To build the window shown in Figure 1, you might write code like the following:
C#
private void CollectionSample()
{
Product prod = new Product();
// Setup the GridView Columns
lstData.View = WPFListViewCommon.CreateGridViewColumns(
prod.GetProperties());
lstData.DataContext = prod.GetProducts();
}
VB.NET
Private Sub CollectionSample()
Dim prod As New Product()
' Setup the GridView Columns
lstData.View = WPFListViewCommon.CreateGridViewColumns( _
prod.GetProperties())
lstData.DataContext = prod.GetProducts()
End Sub
The Product class contains a method called GetProperties that returns a PropertyHeaders collection. You pass this collection to the WPFListViewCommon’s CreateGridViewColumns method and it will create a GridView for the ListView. When you then feed the DataContext property of the ListView the Product collection the appropriate columns have already been created and data bound.
Summary
In this blog you learned how to create a ListView that acts like a DataGrid using a collection class. While it does take a little code to do this, it is an alternative to creating each GridViewColumn in XAML. This gives you a lot of flexibility. You could even read in the property names and header text from an XML file for a truly configurable ListView.
NOTE: You can download the complete sample code (in both VB and C#) at my website. http://www.pdsa.com/downloads. Choose Tips & Tricks, then "WPF ListView as a DataGrid – Part 2" from the drop-down.
Good Luck with your Coding,
Paul Sheriff
** SPECIAL OFFER FOR MY BLOG READERS **
Visit http://www.pdsa.com/Event/Blog for a free eBook on "Fundamentals of N-Tier".
© ASP.net Weblogs or respective owner