【问题标题】:Custom control: How to override default properties?自定义控件:如何覆盖默认属性?
【发布时间】:2018-08-14 08:15:57
【问题描述】:

我创建了一个类似于按钮的自定义控件。 我想覆盖他的默认属性,但是效果很奇怪。

用户控件 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 背后的代码 (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();
        }
    }

结果

但是,当我尝试设置 Background 属性时,它会为控件的背景而不是椭圆着色,当我尝试设置 Content 时,它会覆盖按钮等...

示例:Background="Red"

【问题讨论】:

  • 而不是隐藏基类属性,您应该只使用它们,并将内部元素的属性绑定到它们,例如&lt;Ellipse Fill="{Binding Background, RelativeSource={RelativeSource AncestorType=UserControl}}"/&gt;.
  • 适用于除背景之外的所有属性。它为整个控件着色,而不是椭圆。有没有办法通过重用这个属性来只给椭圆着色?
  • 您必须将 UserControl 的 ControlTemplate 替换为仅包含 ContentPresenter 的控件。

标签: c# wpf properties custom-controls


【解决方案1】:

您可以为UserControl 定义一个ControlTemplate

<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>

使用TemplateBinding作为模板中en元素的属性,你可以设置UserControl的这个属性来改变模板中元素的属性:

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

【讨论】:

    【解决方案2】:

    UserControl 有其 BackroundContent 属性,它们是 DependencyProperties 的包装器。

    您试图在属性之前使用new 关键字来隐藏它们,但它失败了。 (在setter中设置断点:断点永远不会命中)

    当从 xaml 设置 Background="smth"Content="smth" 时,会检测到基本属性,另外 WPF 不使用包装器属性,它直接使用 DependencyObject.SetValue()。并且设置基本内容只是删除现有的带有椭圆的网格。

    重命名背景 -> 自定义背景,内容 -> 自定义内容并设置它们。然后 MyButton 就可以工作了。

    更好的是重用基础内容和背景(将它们绑定到 MyButton xaml 中的 Ellipse 和 Lable)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-12-21
      • 2012-10-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-12-07
      • 1970-01-01
      相关资源
      最近更新 更多