C# 自定义控件库中依赖项属性的WPF组合优于继承

C# 自定义控件库中依赖项属性的WPF组合优于继承,c#,wpf,C#,Wpf,简而言之:我不想在每次编写自定义控件时都实现依赖属性HighlightBrush,从而重复我自己 下面是两个令人讨厌的代码重复示例: public class MyButton : Button { public static readonly DependencyProperty HighlightBrushProperty = DependencyProperty.Register("HighlightBrush", typeof(Brush), typeof(MyButton),

简而言之:我不想在每次编写自定义控件时都实现依赖属性
HighlightBrush
,从而重复我自己

下面是两个令人讨厌的代码重复示例:

public class MyButton : Button
{
    public static readonly DependencyProperty HighlightBrushProperty = DependencyProperty.Register("HighlightBrush", typeof(Brush), typeof(MyButton), new PropertyMetadata(default(Brush)));

    public Brush HighlightBrush
    {
        get { return (Brush) GetValue(HighlightBrushProperty); }
        set { SetValue(HighlightBrushProperty, value); }
    }
}
public class MyTextBox : TextBox
{
    public static readonly DependencyProperty HighlightBrushProperty = DependencyProperty.Register("HighlightBrush", typeof(Brush), typeof(MyTextBox), new PropertyMetadata(default(Brush)));

    public Brush HighlightBrush
    {
        get { return (Brush)GetValue(HighlightBrushProperty); }
        set { SetValue(HighlightBrushProperty, value); }
    }
}
为完整起见,请在
Generic.xaml
中使用
HighlightBrush

<Style TargetType="{x:Type custom:MyButton}">
    <Setter Property="Cursor" Value="Hand" />
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type custom:MyButton}">
                <Border x:Name="Border" Background="{TemplateBinding Background}">
                    <ContentPresenter />
                </Border>
                <ControlTemplate.Triggers>
                    <Trigger Property="IsMouseOver" Value="True">
                        <Setter TargetName="Border" Property="Background" Value="{Binding HighlightBrush, RelativeSource={RelativeSource TemplatedParent}}" />
                    </Trigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

<Style TargetType="{x:Type custom:MyTextBox}">
    <Setter Property="BorderThickness" Value="1" />
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type custom:MyTextBox}">
                <Border x:Name="Border" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}">
                    <ScrollViewer x:Name="PART_ContentHost" />
                </Border>
                <ControlTemplate.Triggers>
                    <Trigger Property="IsFocused" Value="True">
                        <Setter Property="BorderBrush" Value="{Binding HighlightBrush, RelativeSource={RelativeSource TemplatedParent}}" />
                    </Trigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

问题:如何避免依赖属性上的代码重复?我不能引入另一个基类,因为没有多重继承。我不能使用composition,因为依赖项属性需要使用具体类型创建。可能附加的依赖属性有帮助,但如何在控制类和XAML中与它们交互


(我想
TextBlock.Text
TextBox.Text
与我的问题非常相似。)

您可以使用AttachedProperties并在XAML中与它们进行交互,这只需要做更多的工作,您就可以习惯语法

例如,我希望任意控件类型具有
Geometria
(Geometry)属性,因此我创建了一个AttachedProperty类来包含它(葡萄牙语名称):

然后,在XAML中,我将此属性设置为:

        <Button 
            controls:PropriedadeAnexada.Geometria="{StaticResource ÍconeNovoExame}"             
            Style="{StaticResource BotãoGeometria}"
        />
<ControlTemplate 
    x:Key="ControleGeometriaTemplate"
    TargetType="{x:Type Control}"
>
    <Grid x:Name="root">
            <Path
                x:Name="ícone"
                Data="{Binding Path=(local:PropriedadeAnexada.Geometria), RelativeSource={RelativeSource TemplatedParent}}"
            />
    </Grid>
</ControlTemplate>

为了满足我的需要:我仍然必须添加
公共几何HighlightBrush{get{return PropriedadeAnexada.GetGeometria(this);}set{PropriedadeAnexada.SetGeometria(this,value);}
!而是不需要使用
local:PropriedadeAnexada.
前缀绑定。这是一个可以接受的解决方案!好吧,我想如果你想在多个类上重用同一个实现,而不是通过继承,你仍然需要把这个功能(在这种情况下是dependencProperty)放在某个类中,这就是为什么需要静态类作为占位符的原因。此外,由于该属性不在目标类定义中,因此必须使用额外的语法在XAML中引用它。我不知道还有其他方法。不幸的是,这种模式给我带来了很多麻烦:。就我个人而言,我不这样做。但那不是你的错!即使是我也相信解决方案应该有效。。。这是解决方案标记。最后;-)谢谢你的反馈!好的编码!
<ControlTemplate 
    x:Key="ControleGeometriaTemplate"
    TargetType="{x:Type Control}"
>
    <Grid x:Name="root">
            <Path
                x:Name="ícone"
                Data="{Binding Path=(local:PropriedadeAnexada.Geometria), RelativeSource={RelativeSource TemplatedParent}}"
            />
    </Grid>
</ControlTemplate>