Sometimes developers are not able to successfully inject custom features to an already existing user interface component just by inheritance or control template updates.
For example, trying to inherit from Microsoft® WPF’s DataGrid in order to provide graphical drawings based on the items on a side within of the control’s bounds will not work, especially if you want to share code with a Silverlight™ implementation too: DataGrid control’s internal behaviors are very deep and the template re-definitions are not enough either.
In this case, the pattern one could choose would be to both inherit from the base control, but also aggregate an instance of the same base class internally, together with new user interface components – accepting both these relations at the same time: MyDataGrid is a DataGrid and MyDataGrid has a DataGrid.
Maybe weird, but it works. Check out DlhSoft’s GanttChartDataGrid control – it is successfully providing the best API inherited from DataGrid adding its own extra properties and methods, while the output is really a composite user interface presented by an internal DataGrid instance together with a synchronized chart (defined by its default control template).
Of course, the difficult part in this case for the developer is to synchronize the properties and events of the outside DataGrid API that the control inherits with those of the instance it contains. Although it is sometimes trickier than expected, it can be done, at least for the most important part.
A problem that may arise, tough, and can pass virtually unobserved for a very long time, is regarding UI Automation:
You may think that since you are internally using only standard WPF elements, you get UI Automation for granted within your “composite” component. Sometimes, you would be very wrong!
Because of inheritance, the default behavior of UI Automation for your component would be the same as that of the inherited component type, which means that most of the time, “composition” would be out of scope. UI Automation tools will then be unable to investigate the components inside your container.
To resolve this issue, you can override OnCreateAutomationPeer method within your custom control class, and simply return a more basic FrameworkElementAutomationPeer object instead of the base method implementation’s output, which is usually of a more specialized type that is however inappropriate in your case (such as DataGridAutomationPeer in our example).
Since FrameworkElementAutomationPeer automatically provides UI Automation composition browsing, this would be all that you need to do to keep your component cool:
protected override AutomationPeer OnCreateAutomationPeer()
return new FrameworkElementAutomationPeer(this);