Custom controls and user controls

UserControl versus templated Control, control parts and states, dependency properties for reusable controls, and when composition beats templating.

Composition or templating

UserControlTemplated Control
DefinitionXAML plus code-behind, fixed inner treeA default style with a ControlTemplate
RestylingCan only override propertiesThe whole structure can be replaced
Default style lookupNoneThemes/Generic.xaml
Use it forScreens and panels inside your appA control that ships in a library
TestabilityBound to its own DataContextCleaner - the template binds to the control

If the control is application-specific, start with a UserControl. Moving to a templated control later is a rewrite, so make that jump only when consumers genuinely need to replace the visual structure.

A templated control with parts and states

[TemplatePart(Name = PartFill, Type = typeof(Border))]
public class ProgressPill : Control
{
    private const string PartFill = "PART_Fill";
    private Border _fill;

    static ProgressPill()
    {
        DefaultStyleKeyProperty.OverrideMetadata(
            typeof(ProgressPill), new FrameworkPropertyMetadata(typeof(ProgressPill)));
    }

    public static readonly DependencyProperty ValueProperty =
        DependencyProperty.Register(nameof(Value), typeof(double), typeof(ProgressPill),
            new FrameworkPropertyMetadata(0d, FrameworkPropertyMetadataOptions.AffectsRender));

    public double Value
    {
        get => (double)GetValue(ValueProperty);
        set => SetValue(ValueProperty, value);
    }

    public override void OnApplyTemplate()
    {
        base.OnApplyTemplate();
        _fill = GetTemplateChild(PartFill) as Border;   // may be null if the template omits it
    }
}
<!-- Themes/Generic.xaml: the default look for a templated control -->
<Style TargetType="{x:Type local:ProgressPill}">
  <Setter Property="Template">
    <Setter.Value>
      <ControlTemplate TargetType="{x:Type local:ProgressPill}">
        <Border Background="#E6E6E6" CornerRadius="9" Height="18">
          <Border x:Name="PART_Fill" Background="#2F6FED" CornerRadius="9"
                  HorizontalAlignment="Left"
                  Width="{Binding Value, RelativeSource={RelativeSource TemplatedParent}}" />
        </Border>
      </ControlTemplate>
    </Setter.Value>
  </Setter>
</Style>
  • Name parts with a PART_ prefix and declare them with [TemplatePart] - that is the documented contract.
  • OnApplyTemplate can run more than once, so detach from old parts before attaching to new ones.
  • Never assume the part exists; a consumer may supply a template without it. Null-check and degrade.
  • Prefer visual states (VisualStateManager) over triggers inside the template when the control must expose states such as Disabled or Busy.

User controls done well

public partial class SearchBox : UserControl
{
    public static readonly DependencyProperty SearchTextProperty =
        DependencyProperty.Register(nameof(SearchText), typeof(string), typeof(SearchBox),
            new FrameworkPropertyMetadata("", FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));

    public string SearchText
    {
        get => (string)GetValue(SearchTextProperty);
        set => SetValue(SearchTextProperty, value);
    }

    public SearchBox() => InitializeComponent();
}

// SearchBox.xaml: bind the inner text box to the control's own property,
// not to an inherited DataContext you do not control
// <TextBox Text="{Binding SearchText, RelativeSource={RelativeSource AncestorType=local:SearchBox}, UpdateSourceTrigger=PropertyChanged}" />
💡
A UserControl inherits the ambient DataContext, which is convenient inside one screen and a trap inside a reusable one: consumers will set a DataContext and your internal bindings will break. Bind inner elements to the control with RelativeSource AncestorType for anything reusable.

FAQ

Where does Generic.xaml live?
In a Themes folder at the root of the control library, with ThemeInfo declared in AssemblyInfo. Its build action must be Page, and the file name has to be exactly Generic.xaml.
How do I let consumers restyle my control?
Expose dependency properties for the important values and keep the template in the default style. Consumers then override single properties, or supply a whole template, without touching your code.

Dependency properties and routed events Resources, styles, templates and themes

Last refreshed 2026-09-18.