OK, the title of this blog post is not very snappy, but it is not an easy problem to describe in a few short words. Here's the rub, the WPF DataGrid has a select-all button located in the top-left corner, just like Excel and many other grid controls / applications. However, with the default style, this button is barely visible and I would not be surprised if a user of the grid failed to see it.
Unfortunately restyling this button is not all that straightforward. The more complex WPF controls like the DataGrid and ListView typically expose the template used to construct, and the style applied to their various visual elements. However, the DataGrid does not expose a style or template for the select-all button.
Fortunately, all is not lost. With WPF, if a control does not expose a style for one of its component parts, you can replicate and replace its entire template. Sometimes this approach feels a little heavy-handed ... "I can't seem to find a way to fit those flashy alloy wheels to my car, so I'll just by a new car that already has the wheels I like".
I want to explore a more lightweight approach.
Whilst it is usually preferable to modify a controls template from XAML, in cases like this, I prefer the more concise approach of modifying them in code-behind. In order to do this, you need to handle the FrameworkElement.Loaded event on the control whos template you wish to modify. This event is fired after the control's visual tree has been constructed, to verify this add a breakpoint in the event handler and inspect the visual tree with Mole. The image below shows the visual tree of my DataGrid which I have expanded to locate the select-all button.
You can see that the button is the first element, four steps down the visual tree, therefore it should be easy to locate by walking the visual tree. Once it has been reached we can simply replace its template to the one which we desire:
The template SelectAllButtonTemplate is simply defined as a resource of our Window.
This works just fine for our single grid, but what if we want to use the same trick on multiple DataGrids? (Besides, we have code-behind, which in WPF is a bit of a dirty word!).
The Attached Behaviour pattern is a useful WPF pattern that proves very useful in this situation. In brief, attached properties add state to a your WPF elements, whereas attached behaviours add behaviour. When an attached property becomes associated with a dependency object, an event is raised. We can handle this event and register handlers on the events of the object being attached to, in this case, our DataGrid's Loaded event.
The following code is our attached behaviour in its entirety:
This attached property can be used as illustrated below, where we apply the SelectAllButtonTemplate from our Window's resources to a DataGrid:
The result is a beautiful pink select-all button that I don't think any user would miss in a hurry:
And a clean code-behind file for our Window :-)
You can download the demo project for this blog post in the following zip file, wpfstylinghiddenelements.
One last thing ... if you are implementing a WPF / Silverlight control, please expose the styles and templates for all component parts of your control!
Regards, Colin E.