XamDataGrid 101, Part 3 - Data Binding Basics

[Infragistics] Curtis Taylor / Saturday, November 6, 2010
I love the XamDataGrid. I confess. It is an amazing control. There is so much I could tell you about it. So I’ve decided to dedicate another blog to show you the cool things this control can do with data.
One queston users often ask is how do they get their data into the XamDataGrid and what should the data look like. I’m happy to report, the XamDataGrid is highly flexible when it comes to data. You may be working with DataTables already from SQL or a web service. Or you might be a WPF enthusiast using ObservableCollections everywhere.  Both can be used directly with the XamDataGrid. The XamDataGrid can also work with regular Lists and Arrays. I’m also going to tell you about its support for IBindingList and CollectionView.
To start, I’ve whipped up a sample WPF 3.5 project using Visual Studio 2010 and NetAdvantage 2010.3. The sample shows four instances of the XamDataGrid, each with its own binding to a collection property in a ViewModel class. I will use this sample as a reference.
There are two key thing about working with a collection of Records. One is the presentation of the data the other is the data itself. In standard WPF, records of data can be presented in any ItemsControl by using a DataTemplate. However, you must know the data beforehand in order to hard-code the DataTemplate. With the XamDataGrid, you don’t need a DataTemplate. The grid dynamically generates the layout for you with with selectable headers and specialized editors based on the type of each field in the collection of records. You can override this with Field and UnboundField declarations.
The XamDataGrid has an entire Record management system to ensure that the data is presented fast and virtualized. I rarely ever need to explicitly call any of these APIs, however, because I prefer to drive the UI from the data model (or more precisely with a ViewModel class). This means if something other than the UI changes my data, I need the UI to update for me. This also requires that when the UI changes the data, that the underlying model is changed as well. Fortunately, WPF and .NET provides all the tools I need to make this work.
I will show you how to make this work with four types of collections. As I mentioned earlier, the project “SampleGridData” contains a ViewModel with four properties that are bound to four instances of the XamDataGrid in application View. The four properties are composed of types ObservableCollection, CollectionView, BindingList, and DataTable.
I always prefer to have my ViewModel coupled with a View and declared within the XAML directly. And then bound to the DataContext of the main layout Panel in order to reference properties and commands anywhere within that layout. The advantage to this approach is that Visual Studio and Expression Blend will actually instantiate the ViewModel and show the data in the designer. This is huge when working with the XamDataGrid since this is one of those controls that require data in order to show what the presentation of the data will look like in design mode. And speaking of design mode, if your data comes from a service, you can qualify your code with a check for design mode in order to show sample data and not try to call your service when in design mode. This will keep Visual Studio and Blend from trying to do too much. To check that code is being instantiated in the designer, you can call the static method: DesignerProperties.GetIsInDesignMode().
Some things about this sample: the XamDataGrid is refactored into its own UserControl since the same layout construct is repeated four times. The downside to this simplification is that the UserControl view does not have the instance of the ViewModel so you will have to go back to the main window XAML in order to see the data in action in design mode. The sample project also utilized a DispatcherTimer to periodically update the data in order to test dynamic updating of the UI. The amazing thing is that the Timer works in design mode, so while working in the designer you will see the data update while you are working.
The first collection shown in the sample is an ObservableCollection of ‘UserInfo’ objects. ‘UserInfo’ is a simple class composed of three properties to communicate the Username, Password, and Age. The class implements INotifyPropertyChanged. This way when the DispatcherTimer changes the Password property during runtime, the UI will be notified of the change and update dynamically.  ObservableCollection implements INotifyCollectionChanged. That means we don’t have to do anything to notify the UI when items are added or removed from this observable collection. The timer will also add records to the collection at runtime which illustrates that the XamDataGrid bound to this collection will automatically update.
There is a specialized class that can act as a wrapper to collection called CollectionView. WPF uses CollectionView in ItemsControls as a type of implicit ViewModel of your data. This collection wrapper class is used to handle sorting, filtering, grouping and keeping track of the current item. For more information, Bea Stollnitz has a great blog posting about CollectionView. XamDataGrid supports this class so you can take advantage of some of its features.
In the ViewModel class you will see that the ObservableCollection is assigned to the CollectionView as CollectionView is simply a wrapper to your data. As a result, the two XamDataGrids will always be in synch. One feature that the sample shows off is the tracking of the current item. To support this feature, you must enable the ‘IsSynchronizedWithCurrentItem’ property in the XamDataGrid. This will cause the CollectionView.CurrentItem property to return the currently selected Record in the XamDataGrid. To demonstrate this the sample binds CollectionView.CurrentItem to a TextBlock. I’ve also overrode the ToString method in the UserInfo class to return the Username for that record.
The System.ComponentModel assembly contains the BindingList class. This class implements IBindingList. IBindingList is a standard .NET class and users of WinForms will probably be familiar with it. IBindingList supports notification for adding and removing items. The notification model in IBindingList is not supported by standard WPF controls (WPF moved to ObservableCollection). However, to be flexible with existing .NET desktop solutions, XamDataGrid supports this interface.
There is a feature in the XamDataGrid that allows users to add records from within the grid UI itself. This UI will actually instantiate the record and add it to your data. However, to use this feature your collection must implement IBindingList or IEditableCollectionView. Fortunately, the BindingList class implements IBindingList for you and like CollectionView, BindingList wraps another collection. The sample ViewModel does just that, the property for this third grid is a BindingList that wraps the first ObservableCollection.
GridView.xaml enables AllowAddNew:
And the BindingList sample shows the Add Record UI working within the XamDataGrid:
If you decide to take this approach and wrap your collection in BindingList to support the Add New record feature, you must take additional steps to support updating the collection when records are added to the coupled collection and when properties are changed in those records. As you may remember, I have the timer adding records to the ObservableCollection and modifying the Password property. Since the BindingList wrapper does not communicate the notifications directly to the UI, I needed to implement the update myself. To do this I simply needed to implement two event handler methods. One for the CollectionChanged event on the collection and one for the PropertyChanged event for each record in the collection. In the ViewModel you will see both of these events assigned handlers.
UsersObservableCollection.CollectionChanged +=
          UsersObservableCollection_CollectionChanged;

user.PropertyChanged += UsersObservableCollection_PropertyChanged;


For both handlers, I simply communicate to the BindingList to update its binding to the coupled source collection:

UsersBindingList.ResetBindings();


With that change, the changes I make in the first two XamDataGrid instances and by the timer will now be communicated to this third XamDataGrid causing all three to be in-synch.
Finally, the XamDataGrid sample does not synch with the first ObservableCollection at all. In fact, this powerhouse data structure does not use my UserInfo class at all. DataTable is a workhorse object that treats a block of data as tabular rows and columns. This leads to a type of virtual table that takes the place of properties defined for each column. Usually, DataTables are generated automatically from a data base or XML. In this sample, the ViewModel will generate a DataTable programmatically to match the ObservableCollection from the start. I did not go so far as to try to synchronize this table with the others.
When working with DataTables, be aware you do not have a collection of objects such as the ObservableCollection of UserInfo objects. Instead you have a data representation of the UI grid which is simply mapped to the XamDataGrid respective of the ways you define your Columns.
To assign the DataTable to the XamDataGrid, you must use the DefaultView property on the DataTable. DefaultView is of type ‘DataView’. This object is a wrapper on the data which implements IBindingList. This means the DataTable will update when the user changes the data in the view and that you can use the Add New record feature in the XamDataGrid.
DataTable is a powerful feature in .NET and having it accessible to use with XamDataGrid is a huge convenience for many. However, since you do not have a nice class to work with in your ViewModel to implement logic that affect the data, the temptation (for people who need to do those kinds of things) is to place that logic in the code-behind by accessing fields in the records in the UI directly. I always recommend placing your logic in the ViewModel rather than the code-behind as you can better test the code (using unit testing) and will keep the UI data driven. However, I could write a book about all the ways you can use DataTables and best practices for following a data driven model. So instead, I will continue to provide useful tidbits of “killer control” info along the way.
Until next time, have fun with our products – they are truly killer!