简体   繁体   中英

Custom control: How to override default properties?

I've created a custom control similar to a button. I want to override his default properties, but it works strangely.

UserControl Xaml

<UserControl x:Class="project.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">
    <Grid>
        <Ellipse x:Name="structure" Fill="Black" Stroke="White" StrokeThickness="2"/>
        <Label x:Name="content" Content="&#xE081;" VerticalAlignment="Center" HorizontalAlignment="Center" Foreground="White" FontFamily="Segoe MDL2 Assets" FontWeight="Bold" FontSize="16"/>
    </Grid>
</UserControl>

UserControl Code Behind (C#)

    /// <summary>A simple custom button.</summary>
    public partial class MyButton : UserControl
    {
        /// <summary>Background color.</summary>
        public new Brush Background { get => structure.Fill; set => structure.Fill = value; }

        /// <summary>Foreground color.</summary>
        public new Brush Foreground { get => content.Foreground; set => content.Foreground = value; }

        /// <summary>Stroke color.</summary>
        public Brush Stroke { get => structure.Stroke; set => structure.Stroke = value; }

        /// <summary>Stroke thickness.</summary>
        public double StrokeThickness { get => structure.StrokeThickness; set => structure.StrokeThickness = value; }

        /// <summary>Font family.</summary>
        public new FontFamily FontFamily { get => content.FontFamily; set => content.FontFamily = value; }

        /// <summary>Font weight.</summary>
        public new FontWeight FontWeight { get => content.FontWeight; set => content.FontWeight = value; }

        /// <summary>Font size.</summary>
        public new double FontSize { get => content.FontSize; set => content.FontSize = value; }

        /// <summary>Content.</summary>
        public new object Content { get => content.Content; set => content.Content = value; }


        /// <summary>Inizialize new <see cref="MyButton"/>.</summary>
        public MyButton()
        {
            InitializeComponent();
        }
    }

Result

自定义圆形按钮

But, when I try to set the Background property it colors the background of the control, and not the ellipse, when I try to set the Content, it overrides the button, etc...

Example: Background="Red"

背景红

You could define a ControlTemplate for the UserControl :

<UserControl x:Class="project.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" 
             xmlns:local="clr-namespace:WpfApp4"
             mc:Ignorable="d" 
             d:DesignHeight="50" d:DesignWidth="50">
    <UserControl.Template>
        <ControlTemplate TargetType="UserControl">
            <Grid>
                <Ellipse x:Name="structure" Fill="{TemplateBinding Background}" Stroke="White" StrokeThickness="2"/>
                <Label x:Name="content" Content="{TemplateBinding Content}" VerticalAlignment="Center" HorizontalAlignment="Center" Foreground="White" FontFamily="Segoe MDL2 Assets" FontWeight="Bold" FontSize="16"/>
            </Grid>
        </ControlTemplate>
    </UserControl.Template>
</UserControl>

Using a TemplateBinding for a property of en element in the template, you can set this property of the UserControl to change the property of the element in the template:

<local:Button Background="Red" Content="&#xE081;" />

UserControl has its Backround and Content properties, which are wrappers for DependencyProperties.

You are trying to shadow them using new keyword before property, but it fails. (set a breakpoint in setter: breakpoint is never hit)

When setting Background="smth" or Content="smth" from xaml, base properties are detected, and additionally WPF doesn't use wrapper properties, it uses DependencyObject.SetValue() directly. And setting base Content simply removes existing Grid with Ellipse.

Rename Background -> CustomBackground, Content -> CustomContent and set them. Then MyButton will work.

Much better is to reuse base Content and Background though (bind them to Ellipse and Lable in MyButton xaml).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM