Search code examples
c#wpfxamluser-controlsdependency-properties

Binding custom Dependency Property on User Control with ControlTemplate


I've created a custom button with a ControlTemplate.
I used a ControlTemplate to make it possible to bind the default properties of UserControl, such as Background or Foreground.

But, if I add custom dependency properties (for example CornerRadius) I get two errors:

  1. "The member 'CornerRadius' is not recognized or is not accessible."
  2. "Cannot find the static member 'CornerRadiusProperty' on the type 'UserControl'."

Xaml:

<UserControl x:Class="MyProject.MyButton"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
         mc:Ignorable="d" 
         d:DesignHeight="50" d:DesignWidth="50"
         BorderThickness="1" BorderBrush="White" Background="Black"
         Content="OK" Foreground="White">
    <UserControl.Template>
        <ControlTemplate TargetType="UserControl">
            <Border Name="ground"
                    BorderThickness="{TemplateBinding BorderThickness}"
                    BorderBrush="{TemplateBinding BorderBrush}"
                    Background="{TemplateBinding Background}"
                    CornerRadius="{TemplateBinding CornerRadius}">
                <Label Name="content"
                       VerticalContentAlignment="Center" 
                       HorizontalContentAlignment="Center"
                       Content="{TemplateBinding Content}"
                       Foreground="{TemplateBinding Foreground}"
                       FontFamily="{TemplateBinding FontFamily}"
                       FontWeight="{TemplateBinding FontWeight}"
                       FontSize="{TemplateBinding FontSize}"/>
            </Border>
        </ControlTemplate>
    </UserControl.Template>
</UserControl>

Code behind:

namespace MyProject
{
    public partial class MyButton : UserControl
    {
        public static readonly DependencyProperty CornerRadiusProperty =
            DependencyProperty.Register("CornerRadius", typeof(CornerRadius), typeof(MyButton));

        public CornerRadius CornerRadius
        {
            get => (CornerRadius)GetValue(CornerRadiusProperty);
            set => SetValue(CornerRadiusProperty, value);
        }


        public MyButton() => InitializeComponent();
    }
}

If I use the solution specified here User control with custom properties I get this problem Wpf - Custom control: How to override default properties?.

So, there is a solution that avoid both problems?


Solution

  • A custom Button should not be a UserControl, but instead directly derive from Button.

    Add a "Custom Control (WPF)" to you Visual Studio Project and modify it like this:

    public class MyButton : Button
    {
        static MyButton()
        {
            DefaultStyleKeyProperty.OverrideMetadata(
                typeof(MyButton),
                new FrameworkPropertyMetadata(typeof(MyButton)));
        }
    
        public static readonly DependencyProperty CornerRadiusProperty =
            DependencyProperty.Register(
                nameof(CornerRadius), typeof(CornerRadius), typeof(MyButton));
    
        public CornerRadius CornerRadius
        {
            get => (CornerRadius)GetValue(CornerRadiusProperty);
            set => SetValue(CornerRadiusProperty, value);
        }
    }
    

    Then change its default Style in the generated Themes\Generic.xaml file:

    <Style TargetType="local:MyButton">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="local:MyButton">
                    <Border Name="ground"
                            BorderThickness="{TemplateBinding BorderThickness}"
                            BorderBrush="{TemplateBinding BorderBrush}"
                            Background="{TemplateBinding Background}"
                            CornerRadius="{TemplateBinding CornerRadius}">
                        <Label Name="content"
                               VerticalContentAlignment="Center" 
                               HorizontalContentAlignment="Center"
                               Content="{TemplateBinding Content}"
                               Foreground="{TemplateBinding Foreground}"
                               FontFamily="{TemplateBinding FontFamily}"
                               FontWeight="{TemplateBinding FontWeight}"
                               FontSize="{TemplateBinding FontSize}"/>
                    </Border>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
    

    See Control Authoring Overview for details.