HexViewer control is designed for viewing any collection of bytes in the customary hexadecimal form: each line of text displays 16 bytes and has an address pane at the left, hexadecimal pane in the middle and text pane at the right. It's just the viewer – it hasn't any editing or even selecting/copying capabilities.
HexViewer is the full-fledged WPF control supporting templates and themes. It relies on template (customer provided or default theme one) to plug-in its core functionality into the template element tree and uses named template part (sort of PART_) to fulfil this task, like many built-in WPF controls do.
The primary motivation that pushed me to place this article at the CodeProject is to give one answer to the question: what should happen if the control template misses required named element or it has an inappropriate type? Other reasons: this control can be useful (1) by itself and (2) as the sample on elements composition and simple element tree manipulations. In my opinion, neither printed WPF books nor Internet are yet overcrowded with these sort of samples.
WPF controls and control templating is the great approach allowing us completely change control look and feel without any need to touch control internals. There are some drawbacks, however.
Some built-in WPF controls (i.e. provided by Microsoft) rely on templates to plug-in their core functionality into a template-provided element tree. If the template isn't constructed properly from templated control point of view, then an attempt to bring in that core functionality fails and the control becomes unusable.
Let's take a close look at the
TextBox control which seems to be the closest to
HexViewer among other built-in controls.
TextBox control is derived from
TextBoxBase. The latter is marked with
TemplatePartAttribute(Name="PART_ContentHost", Type=typeof(FrameworkElement)), i.e.
TextBox control expects to find an element named as
PART_ContentHost in its template element tree. This element type can't be any type derived from
FrameworkElement, however: MSDN topics on
TextBox define more exactly that it should be either
AdornerDecorator (there is a little contradiction in MSDN documentation: in one place it's stated that Content Host may be of any type derived from
Decorator, not just the
AdornerDecorator; experiments show that this statement is right: e.g. we can use
Border in place of
AdornerDecorator). That's how
TextBox default template under Windows Vista Aero theme (I got it with the help of Charles Petzold
DumpControlTemplate tool from his Applications = Code + Markup book) looks like:
<mwt:ListBoxChrome . . . >
<ScrollViewer Name="PART_ContentHost" . . . />
(details not pertaining to our discussion are stripped out)
TextBox default Aero visual tree:
If we replace
ScrollViewer in the template above with
AdornerDecorator we'll get the visual tree:
TextBoxView element which appears under
PART_ContentHost element in both visual trees above. It's derived form
FrameworkElement, isn't publicly accessible and isn't documented. If we remove
Name="PART_ContentHost" attribute from the template or just change its value to something else than "
TextBoxView disappears from the Visual Tree and all
TextBox text displaying/editing functionality goes out (no text, no caret, no text input …). It seems to be legal to suppose that this
TextBoxView element plays an important role in
TextBox implementation and that
TextBox control uses its template
PART_ContentHost named part to plug in
TextBoxView into the Visual Tree to content host provided.
One more thing: as soon as we replace Content Host with something other than
ScrollViewer or a derivative from
Decorator then the
TextBox creation process will fail with
NotSupportedException raised by
TextBoxBase.SetRenderScopeToContentHost() method with the message like "Only Decorator or ScrollViewer elements can be used as
PART_ContentHost" (it's the back translation from Russian so the original message can differ).
Well, Microsoft WPF control design guidelines are expounded in the Guidelines for Designing Stylable Controls document. That's an excerpt from it:
1. Do not strictly enforce template contracts. The template contract of a control might consist of elements, commands, bindings, triggers or even property settings that are required or expected for a control to function properly.
· Do not throw exceptions when any aspect of a template contract is not followed. …
Is there some inconsistency between Microsoft intentions and the practice?
To me as a control author it seems reasonable to provide some visual cue in case the control template supplied doesn't match the control requirements and strips out its core functionality. This visual cue should be a part of the control and shows up above the template provided visuals. That's how
HexViewer control is designed.
HexViewer consists of two parts
HexView is derived from
FrameworkElement, is internal and is rather trivial. It's responsible for data formatting into text lines and for their rendering.
HexViewer is public and is responsible for plugging internal
HexView part into a template provided by control customer (or into a default theme template). This goal is controlled by the use of template
PART_ContentHost named part, the same way as
HexViewer allows for the same Content Host element types, as
TextBox does: Content Host could be either of the
ScrollViewer type (the default) or could be any derivative from
Decorator type (like
HexViewer has to implement this behaviour is to override
public override void OnApplyTemplate()
object contentHost = Template.FindName("PART_ContentHost", this);
if (contentHost != null)
if (contentHost.GetType() == typeof(ScrollViewer))
m_hv = new HexView();
(contentHost as ScrollViewer).Content = m_hv;
else if (contentHost is Decorator)
m_hv = new HexView();
(contentHost as Decorator).Child = m_hv;
if (m_hv != null)
Binding paddingBinding = new Binding("Padding");
paddingBinding.Source = this;
(Note: m_hv private field is of HexView type)
In the first part of this code, after the template is created and applied,
HexViewer tries to find
PART_ContentHost in it. If find succeeds and if the
contentHost is the
ScrollViewer or a derivative from
Decorator then new
HexView object is created and added to the
contentHost as its content. Otherwise
HexView object isn't created and
HexViewer control doesn't show up its core functionality. This short code implements the same templating behavior as
TextBox has except it doesn't throw an
contentHost has an inappropriate type.
The second block of the code, if
HexView object isn't created, calls
ApplyUglyTemplateCue() function (and this behavior is different from that of
private void ApplyUglyTemplateCue()
m_UglyTemplateCue = FindResource("uglyTemplateCue") as UIElement;
if (m_UglyTemplateCue == null)
Border cue = new Border();
cue.Margin = new Thickness(5);
cue.VerticalAlignment = VerticalAlignment.Top;
cue.BorderBrush = Brushes.Red;
cue.BorderThickness = new Thickness(2);
cue.Background = SystemColors.WindowBrush;
cue.Opacity = 0.5;
cue.Padding = new Thickness(2);
TextBlock txt = new TextBlock();
txt.Foreground = Brushes.Red;
txt.Text = "Ugly Template warning: template provided hides
HexViewer control (missed PART_ContentHost
element of type ScrollViewer or AdornerDecorator)";
txt.TextWrapping = TextWrapping.Wrap;
cue.Child = txt;
m_UglyTemplateCue = cue;
(Note: m_UglyTemplateCue private field is of UIElement type)
ApplyUglyTemplateCue() function creates a visual Ugly Template Cue element used to notify the
HexViewer user that the control template is inappropriate and stores it in a
private field. To make this
HexViewer aspect stylable
HexViewer has to allow the customer to provide its own Ugly Template Cue element. I decided to use a resource for that end: a customer can define any visual element (derived from
UIElement) somewhere in an application resource tree and tag it with "
uglyTemplateCue" key (don't forget to apply
x:Shared="True" attribute to it if it could happen to be used by multiple
HexViewer instances). If "
uglyTemplateCue" resource isn't found then
ApplyUglyTemplateCue() function creates default Ugly Template Cue element. Then the element is registered with Visual and Logical Trees.
Now we have to plug Ugly Template Cue element (if there is one) into
HexViewer visual tree. To do that we have to override
VisualChildrenCount property and
ArrangeOverride methods (I would like to emphasize: we shouldn't override these methods if we wouldn't implement Ugly Template Cue notification). One thing to remember: don't omit call to base versions of these methods!
protected override int VisualChildrenCount
return base.VisualChildrenCount + (m_UglyTemplateCue == null ? 0 : 1);
base.VisualChildrenCount will return
0 before the template is applied and
1 after that.
protected override Visual GetVisualChild(int index)
return index < base.VisualChildrenCount ?
base.GetVisualChild(index) : m_UglyTemplateCue;
It's important that
GetVisualChild returns Ugly Template Cue (if any) as the last element of this Visual Tree level. Otherwise it could be hidden by template-provided elements.
The last thing to do are layout methods overrides:
protected override Size MeasureOverride(Size sizeAvailable)
Size sizeDesired = base.MeasureOverride(sizeAvailable);
if (m_UglyTemplateCue != null)
protected override Size ArrangeOverride(Size sizeFinal)
if (m_UglyTemplateCue != null)
m_UglyTemplateCue.Arrange(new Rect(0, 0, sizeFinal.Width,
Using the code
The source code for this article consists of VS 2005 SP1 solution with two projects: one for
HexViewer control library and the other for the test application. It is compiled and tested under Windows Vista with .NET 3.0 preinstalled. Frankly, I haven't compiled it in any other environment.
HexViewer control accepts input data (to visualize in hexadecimal) through
Data dependency property of
IEnumerable<byte /> type.
HexViewer isn't optimized to work with large data: it doesn't implement any virtualization, etc. This implementation aspect is intentionally left as simple as possible.
Theming support includes only generic and Aero dictionaries.