This blog post reviews a technique that can vastly reduce the amount of screen real estate required to display your application’s data in XamDataGrid.
In my previous post on this blog, I showed how to display an extra field of data in the adorner layer, instead of putting it into a XamDataGrid cell. Since writing that post, I have spent the entire weekend blissfully working on and expanding that core concept. I managed to extract all of the plumbing code that hosts an editor in the adorner layer into a reusable class. I also vastly enhanced and thoroughly tested this functionality. In this blog post, I am proud to present the fruit of my labor: a new behavior for XamDataGrid called ‘DisplayAdorningEditors’.
Before going forward, let’s first take a step back and review why I built this behavior. Most applications have a core subset of data that users refer to most. When displaying data in a data grid, such as XamDataGrid, it can be tempting to simply display all of the data fields as separate columns in the grid. This is convenient because it takes less time to set up, but in the bigger picture, this is usually not a good idea.
There are, at least, two problems with this approach. The user experience degrades because your users must now look at and sift through reams of irrelevant data. Most people appreciate only seeing what they typically want to see, as long as finding the less frequently needed information is not a challenge. In addition, either showing large amounts of data fields in a data grid requires the grid to be very wide, in which case it uses up more precious screen real estate, or it requires the dreaded horizontal scrolling (which most UI designers generally deem a bad thing).
Ideally, you should only display the most relevant data in XamDataGrid, but make it easy for users to find the other, less frequently used information. This improves the user experience and reduces the amount of screen real estate required by the grid. My DisplayAdorningEditors behavior for XamDataGrid makes it easy to achieve this worthwhile goal.
I created a class called XamDataGridBehavior. That class can attach a behavior to XamDataGrid. The attached behavior’s name is DisplayAdorningEditors. When you attach this behavior to a XamDataGrid, you can specify a control to display in the adorner layer directly next to the active cell in the grid. In case you are not familiar with WPF’s adorner layer yet, think of it as a pane of glass on top of your UI, in which any visual elements can render, and it is certain that they will draw on top of the UI underneath (“on top of” with regards to the Z axis, not the Y axis).
Setting the DisplayAdorningEditors attached property to true on the XamDataGrid is only half the battle. You must assign a handler for the RequestAdorningEditor attached event, also exposed by my XamDataGridBehavior class. Your event handling method is invoked when the DisplayAdorningEditors behavior needs to know what control, if any, to display in the adorner layer for the grid’s active cell (i.e. the value returned by its ActiveCell property). Be aware, that event is raised quite often, so your application logic should always provide the same control instance(s), instead of new’ing up fresh control instances every time.
You can set this up in XAML, as seen in the following excerpt from the demo application’s ContaxControl user control:
Here is that user control’s code-behind file:
public partial class ContaxControl : UserControl
readonly ContactEmailControl _contactEmailControl;
readonly ContactPhoneNumbersControl _contactPhoneNumbersControl;
readonly ContactPhotoAndNotesControl _contactPhotoAndNotesControl;
_contactEmailControl = new ContactEmailControl();
_contactPhoneNumbersControl = new ContactPhoneNumbersControl();
_contactPhotoAndNotesControl = new ContactPhotoAndNotesControl();
base.DataContext = Contact.CreateContacts();
void OnRequestAdorningEditor(object sender, RequestAdorningEditorRoutedEventArgs e)
e.AdorningEditor = _contactPhotoAndNotesControl;
e.AdorningEditor = _contactPhoneNumbersControl;
e.AdorningEditor = _contactEmailControl;
Debug.Fail("Unexpected Field: " + e.AdornedCell.Field.Name);
if (e.AdorningEditor != null)
e.AdorningEditor.DataContext = e.AdornedCell.Record.DataItem;
Another hing to take note of is that your controls hosted in the adorner layer need to have some logic built in that handles keyboard navigation. Since you can use any type of control as an adorning editor, my attached behavior cannot make any assumptions about how to handle keystrokes aimed at your control. If you would like to see an example of how to implement this, in the demo application the keyboard interaction logic is in the ContactAdornerControlBase class.
Also, if you want my XamDataGridBehavior class to move focus to your adorning editor control when the user presses Tab, you must set your control's IsTabStop property to true. If you do not, it is assumed that the user should not be able to navigate into the adorning editor control via the Tab key.
Contax - The Demo Application
The best way to understand what this new behavior can do, and how to use it, is to look at the Contax demo application. Contax is a very simple application that stores a list of personal contact information. All of the data is read-only, except for the optional notes about each contact. The point of this demo is not to see how to build a full-fledge application, but simply to see how to use the DisplayAdorningEditors behavior with XamDataGrid.
This screenshot shows Contax when it first starts up:
The XamDataGrid seen above shows four pieces of information about each contact in the list: gender, name, mobile phone number, and personal e-mail address. The assumption is that the users of Contax would find that information to be the most pertinent to their average use of the program. Naturally, deciding on what information is most pertinent for most users requires, for a real application, market research, user acceptance testing, and other related activities.
Now suppose that the user wants to know more about one of the contacts, perhaps Patricia McClellan. After clicking on Patricia’s cell in the “name” column, the UI discloses more information about her, as seen below:
As seen above, we can now see a photograph, nickname, and notes about Patricia (a.k.a. Trish). If Trish’s photo, nickname, and notes were displayed as separate columns in the data grid, the grid’s width would be considerably larger, and the users would have to look at information that they probably don't care about too often.
At this point, the user decides to give Steven Rottingham a call. She first calls his mobile phone, but Steven does not answer, so she decides to call his office phone instead. To find Steven’s office number, the user clicks on the cell in the “mobile #” column to bring up a list of all phone numbers associated with Steven. Here’s what that looks like:
Now the user decides to send Joe Barkley an e-mail, so she opens his list of e-mail addresses to find the right one. After deciding which address to send the message to, she clicks the button next to that address and her default e-mail client opens up with that address in the To field.
If the user were to shorten the Contax window, and then click on Michelle’s name, the adorning editor displays above Michelle’s row, since there is not enough room to display it underneath.
You can download the source code and demo application here (4.27 MB). The solution compiles in Visual Studio 2008 against NetAdvantage for WPF v8.1.