The data in the grid was originally copied from an actual iTunes library, and then serialized to an XML file which is included in the project as a resource. We load the data into an ICollectionView object with code that looks like this:
C# |
Copy Code
|
---|---|
// load the data List <Song> songs = LoadSongs(); // create ICollectionView var view = new PagedCollectionView(songs); // group songs by album and artist using (view.DeferRefresh()) { view.GroupDescriptions.Clear(); view.GroupDescriptions.Add(new PropertyGroupDescription("Artist")); view.GroupDescriptions.Add(new PropertyGroupDescription("Album")); } // use converters to format song duration and size fg.Columns["Duration"].ValueConverter = new SongDurationConverter(); fg.Columns["Size"].ValueConverter = new SongSizeConverter(); // bind data to grid fg.ItemsSource = view; |
The code uses a LoadSongs helper method that loads the songs from the XML file stored as a resource. In a real application, you can replace this with a web service that loads the song catalog from a server. Here is the implementation of the LoadSongs method:
C# |
Copy Code
|
---|---|
public static List<Song> LoadSongs() { // find assembly resource var asm = Assembly.GetExecutingAssembly(); foreach (var res in asm.GetManifestResourceNames()) { if (res.EndsWith("songs.xml")) { using (var stream = asm.GetManifestResourceStream(res)) { // load song catalog using an XmlSerializer var xmls = new XmlSerializer(typeof(List<Song>)); return (List<Song>)xmls.Deserialize(stream); } } } return null; } |
The Song class stores song durations in milliseconds and sizes in bytes. This is not a convenient format to show to users, and there is not a simple .NET format string that converts the values to what we want. Instead of setting the Column.Format property, the code above sets the Column.ValueConverter property for the Duration and Size columns instead.
The Column.ValueConverter property specifies an IValueConverter object used to convert raw data values into display values for the column. Here is our sample implementation of value converters for song durations (expressed in milliseconds) and size (expressed in bytes):
C# |
Copy Code
|
---|---|
// converter for song durations (stored in milliseconds) class SongDurationConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { var ts = TimeSpan.FromMilliseconds((long)value); return ts.Hours == 0 ? string.Format("{0:00}:{1:00}", ts.Minutes, ts.Seconds) : string.Format("{0:00}:{1:00}:{2:00}", ts.Hours, ts.Minutes, ts.Seconds); } public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { throw new NotImplementedException(); } } // converter for song sizes (returns x.xx MB) class SongSizeConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { return string.Format("{0:n2} MB", (long)value / 1024.0 / 1024.0); } public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { throw new NotImplementedException(); } } |
The first value converter uses distinct formats for durations that last over an hour; the second divides the byte counts to get megabytes. IValueConverter objects are flexible, simple, and very common in WPF programming.
That's all we have to do as far as data binding. We now have a proper ICollectionView data source and columns that show song name, duration, and size using a convenient format.