WPF rewrites the book on Windows programming. When you decide to develop for WPF, then you can say goodbye to device contexts, selecting pens and brushes into device contexts, BITBLTs and compatible device contexts, window handles, owner draw buttons and listboxes, and ActiveX controls. WPF completely overturns the classic approach to developing Windows applications and adds user interface flexibility and pizzazz unavailable to Windows developers up to now.
One of the ways in which WPF redefines Windows programming is the way in which it implements controls. While the 10,000 foot view of controls looks familiar (i.e. WPF controls have state, behaviour, and events), the WPF architecture underneath is completely new. Of course, any user interface technology worth its salt will have a component / control model, and WPF is no different. This article focuses on the WPF control architecture and how to implement custom controls within WPF.
The classic Windows control architecture has evolved significantly over the last couple of decades. The first implementation of Windows controls used the classic Windows message loop/Window procedure architecture. That is, classic Windows controls (such as the Button, the ListBox, and the ComboBox) had their own Windows procedures buried in a DLL somewhere (for the basic controls, this was User32.DLL). If you wanted to create your own completely new control, you’d write your own child window and create a Window procedure to implement it. To change the behaviour of an existing control, you’d subclass the control. In certain cases, you could change the presentation area of a Button, a ListBox, or a ComboBox using owner-draw techniques.
Later control architectures included the early Visual Basic controls (VBXs) and ActiveX controls popular during the late 90’s. ActiveX controls aimed to provide a language/tool agnostic approach to creating custom controls.
These approaches all define ways for controls to exhibit behaviour, state, and events within source code. However, anyone who’s worked with WPF and XAML for any length of time knows how much emphasis WPF puts on the declarative aspect of User Interface development. XAML represents a way to develop a User Interface declaratively by defining a logical tree of controls and framework elements, and it’s reflected in the WPF control story.
Of course, WPF includes all the standard controls we’ve come to know and love over the last 25 years. WPF controls (by most appearances) look and behave like the standard windows controls. However, they’re different because they’re constructed using a WPF Visual Tree and they expose Routed Events (rather than normal .NET Events).
WPF and DataTemplates
WPF controls also support data binding through DataTemplates. This is WPF’s answer to standard Win32 owner-draw controls. DataTemplates represent a way to associate specific presentation instructions to a certain data type. For example, if you’d like the items within a ListBox to appear a specific way when a certain data type is rendered by the ListBox, you may define a specific DataTemplate for the ListBox’s ItemTemplate property based on the specific data type. The ItemTemplate might layout a StackPanel composed of TextBlocks and Image controls that are bound to the data type held by the control. This greatly simplifies custom rendering for WPF Controls
WPF Control Visual Trees
In addition to providing a standard way to associate presentation instructions with specific data types, the WPF control architecture provides a standard way to modify the appearance of a control without changing its fundamental behavior. WPF defines controls using separate components that may be swapped in and out. It’s possible to completely change the appearance of a control by replacing the ControlTemplate. More complex controls like the ListBox and ComboBox include ControlTemplates in addition other parts of the Visual tree that may be swapped out to change the control’s appearance.
WPF User Control
WPF User Controls represent a way to collect controls together and package them into re-usable XAML. In the past (pre .NET) these have been called composite controls. .NET defines the concept of composite controls as User Controls (Windows Forms and ASP.NET define User Controls, as well). User Controls are useful for packaging several UI elements together into one declaration so all the controls may be used together en-masse. (For example, imagine a login control consisting of two Labels, two TextBoxes, and Buttons for OK and Cancel—that’s a good example of a User Control).
WPF Custom Controls
The rest of this article covers how to create controls from scratch. Before proceeding, remember that the WPF architecture already includes the following facilities for customizing controls:
- Polymorphic content—from a simple TextBlock all the way to a fully-composed layout panel
- DataTemplates for modifying the data presentation within a control
- A Visual Tree composed of parts that may be swapped out to change the overt appearance of the control
- User Controls for grouping and packaging controls
If what you’re trying to do cannot be accomplished using one of the techniques listed above, then consider creating a custom control from scratch. Writing a control from scratch requires more work, but when you take this route, you assume complete control over the appearance and the behaviour of the control.