While testing my new Custom Window control (which I should be blogging about soon) I ran into an interesting problem. The custom window control derives from System.Windows.Window and has its own ControlTemplate defined in its generic.xaml file. Now I have an application that makes use of Drag ‘n’ Drop (DnD) and was previously using the regular Window control. When I replaced that with my custom window control, the app would just crash as soon I started dragging some elements. Note that the same DnD code would work with the regular Window control.
Initially I suspected that there may be a bug in my DnD code, but the bug lied somewhere else. It was in the ControlTemplate for the custom window control. Huh?
The DnD code makes heavy use of Adorners and the AdornerLayer for showing the drag feedback. For the adorners to work, there has to be an AdornerLayer somewhere up in the Object Tree, since it acts as the rendering surface for the adorners. The API for retrieving an AdornerLayer is the static method
AdornerLayer.GetAdornerLayer(Visual elt)
The reason why this API would work for the regular Window and not for my custom window was because of the magic element called AdornerDecorator. For the Window control (which is a ContentControl), the ContentPresenter is surrounded by an AdornerDecorator, which ensures the success of the above API call, like so:
<ControlTemplate TargetType="{x:Type Window}">
<Border BorderBrush="{TemplateBinding Border.BorderBrush}"
BorderThickness="{TemplateBinding Border.BorderThickness}"
Background="{TemplateBinding Panel.Background}">
<Grid>
<AdornerDecorator>
<ContentPresenter ContentTemplate="{TemplateBinding
ContentControl.ContentTemplate}"
Content="{TemplateBinding ContentControl.Content}" />
</AdornerDecorator>
.....
.....
</ControlTemplate>
The ControlTemplate that I defined did not have it and that used to crash the DnD code. So if you find yourself designing a ControlTemplate for a Window, make sure you Don’t forget the AdornerDecorator;)