I'm trying to have a custom WPF control whose content is defined in XAML but avoiding the use of a UserControl. This is because a UserControl makes it impossible to add x:Name to its content: https://stackoverflow.com/questions/751325/how-to-create-a-wpf-usercontrol-with-named-content/3413382

My files are laid out like this:

│   App.config
│   App.xaml
│   App.xaml.cs
│   MainWindow.xaml
│   MainWindow.xaml.cs
│   WpfScratch.csproj
│   ├───Debug
│   │   │   WpfScratch.exe
│   │   │   WpfScratch.exe.config
│   │   │   WpfScratch.pdb
│   │   │
│   │   └───Controls
│   └───Release
.       MyPanel.cs
.       MyPanel.xaml

and the source of the relevant ones is:


public class MyPanel : Control
    static MyPanel()
        DefaultStyleKeyProperty.OverrideMetadata(typeof(MyPanel), new FrameworkPropertyMetadata(typeof(MyPanel)));

    public MyPanel()
        var templateUri = new Uri("/WpfScratch;component/Controls/MyPanel.xaml", UriKind.Relative);
        Template = (ControlTemplate) Application.LoadComponent(templateUri);

    public static readonly DependencyProperty BodyProperty = DependencyProperty.Register("Body", typeof(object), typeof(MyPanel), new PropertyMetadata(default(object)));

    public object Body
        get => GetValue(BodyProperty);
        set => SetValue(BodyProperty, value);

    public static readonly DependencyProperty FooterProperty = DependencyProperty.Register("Footer", typeof(object), typeof(MyPanel), new PropertyMetadata(default(object)));

    public object Footer
        get => GetValue(FooterProperty);
        set => SetValue(FooterProperty, value);


<ControlTemplate xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                 TargetType="local:MyPanel" >
    <DockPanel LastChildFill="True" x:Name="Content">
        <Border BorderThickness="2"
            <ContentPresenter x:Name="Footer"
                              Content="{Binding Footer, RelativeSource={RelativeSource TemplatedParent}}"
                              Margin="0, 10" />
        <Border BorderThickness="2"
            <ContentPresenter x:Name="Body" 
                              Content="{Binding Body, RelativeSource={RelativeSource TemplatedParent}}" />


<Window x:Class="WpfScratch.MainWindow"
        Title="MainWindow" Height="450" Width="800">
    <controls:MyPanel x:Name="HelloWorldPanel">
            <Label x:Name="HelloLabel">Hello!</Label>
            <Label x:Name="WorldLabel">World!</Label>

My main concern is the loading of the XAML file, i.e.:

 var templateUri = new Uri("/WpfScratch;component/Controls/MyPanel.xaml", UriKind.Relative);
 Template = (ControlTemplate) Application.LoadComponent(templateUri);
  1. Is Application.Load() the way to go? UWP seems to deprecate it in favour of XAMLReader.Load(), but I'm not sure how I would get the correct stream for that. I tried digging into the sources of Application.LoadComponent and there's some logic involved with processing pack URIs
  2. The URI is a hardcoded mouthful and seems not very resilient to refactoring. Is there a terse way of saying "hey my XAML file is right next to this one"?
  • \$\begingroup\$ I can't see where the name is being used. Am I overlooking something? Is it used in code which you haven't included in the question? \$\endgroup\$ Jul 30, 2018 at 11:01
  • \$\begingroup\$ @Peter - which name? \$\endgroup\$
    – millimoose
    Jul 30, 2018 at 11:03
  • \$\begingroup\$ Any of them. You say that the reason for avoiding UserControl is that it prevents you using names, but I can't see why any of the names in the code is actually necessary. All of the binding seems to be to properties rather than elements. \$\endgroup\$ Jul 30, 2018 at 11:06
  • \$\begingroup\$ @PeterTaylor - code clarity and being able to navigate the visual tree easier when debugging \$\endgroup\$
    – millimoose
    Jul 30, 2018 at 11:07
  • \$\begingroup\$ And yes, obviously it would be useful if I needed to identify the control in codebehind, but that’s not my use case yet and I was motivated by the previous reasons to look into this, since it’s a vexing restriction with a confusing error message \$\endgroup\$
    – millimoose
    Jul 30, 2018 at 11:08

1 Answer 1


The conventional way of attaching default template to custom control is to specify default style inside a special resource dictionary. For this approach to work three conditions should be met:

1) Resource dictionary should be located at Themes/Generic.xaml. There you should place a default style for your custom control (that in turn should set Template property to default value).

2) Your AssemblyInfo.cs file should contain ThemeInfoAttribute.

3) Your custom control should override default style key inside a static constructor, using DefaultStyleKeyProperty.OverrideMetadata method.

Alternatively, if you are not planning on reusing your custom control, you can just drop the default style into App.xaml resources and avoid above shenanigans.

For more info see: https://michaelscodingspot.com/2016/12/24/explicit-implicit-and-default-styles-in-wpf/

  • \$\begingroup\$ Will this work is this control is in a subproject that’s referenced by the main app’s project in a solution? That is, is the theme tied to the assembly rather than the app itself? \$\endgroup\$
    – millimoose
    Jul 30, 2018 at 11:06
  • 2
    \$\begingroup\$ @millimoose, the three points are for using it as a subproject. The line beginning "Alternatively" is the simpler approach which suffices if you just want to tie the theme to the app. \$\endgroup\$ Jul 30, 2018 at 11:07
  • \$\begingroup\$ @millimoose, yes, first approach will work "out of the box": you will be able to use your custom controls the same way you use default ones - just by referencing them in your xaml. Second approach will technically work as well, but you would have to manually specify path to resource dictionary inside App.xaml every time you create a new application that depends on your sub-project. For that reason I wouldn't recommend using it across different assemblies. \$\endgroup\$
    – Nikita B
    Jul 30, 2018 at 11:17

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.