如何继承控件模板

22

我正在开发一个 WPF 项目,在其中我覆盖了 CheckBox 控件以进行特殊操作。这部分功能已经正常工作。

我的问题是,从主题应用的 ControlTemplate(来自 codeplex 的 shinyred.xaml)没有被应用到我覆盖后的控件上。是否有一种方法可以继承 CheckBoxControlTemplate 以供我的新控件使用?

我找到的所有示例都集中在为CheckBox继承样式,但没有关于 ControlTemplate 的内容。

2个回答

23
不行,就像你所说的,使用BasedOn属性可以“继承”样式,但是直接“继承”模板是不可能的。这是可以理解的,因为模板继承的语义会是什么呢?派生模板如何能够在基础模板中添加或更改元素呢?
对于样式来说,完全有可能,因为您只需添加Setters、Triggers等即可。唯一可能实现的模板继承是将触发器添加到基本模板中。然而,在这种情况下,您必须熟悉基础模板中的元素名称,并且基础模板中的元素名称更改可能会破坏您的派生模板。更不用说可读性问题了,您引用了派生模板中某个其他地方定义的名称。
晚点补充:说了这么多,解决您的特定问题是可能的(尽管我怀疑现在它已经不再是您的问题,甚至不再是问题)。您只需为控件定义一个样式,并为Template属性设置一个Setter。
<Style TargetType="<your type>">
    <Setter Property="Template" Value="{StaticResource <existing template resource name>}"/>
</Style>

1
然而,在这种情况下,您必须对基本模板中的元素名称有深入的了解,而基本模板中的元素名称更改可能会破坏您的派生模板。更不用说可读性的问题了,您在派生模板中引用一个在其他地方定义的名称。这不是继承通常的情况吗? - Jeff
这更像是从函数实现继承,而不是从类型定义继承。 - Aviad P.
@Jeff,是的,但仅适用于基类的公共和受保护元素。但似乎正确的类比是ControlTemplate的内容是“私有的”。 - StayOnTarget

3

记住@Aviad所说的,以下是一个解决方法:

假设你有一个定义了模板的Button,你想要继承它,那么就像这样将你的CustomButton定义为自定义控件:

public class CustomButton : Button
{

    static CustomButton()
    {
        DefaultStyleKeyProperty.OverrideMetadata(typeof(CustomButton), new FrameworkPropertyMetadata(typeof(CustomButton)));
    }


    public static readonly DependencyProperty TextProperty = DependencyProperty.Register("Text",
        typeof(string),  typeof(CustomButton), new UIPropertyMetadata(null));

    public string Text
    {
        get { return (string)GetValue(TextProperty); }
        set { SetValue(TextProperty, value); }
    }
}

然后转到您的Generic.xaml并定义以下内容:

 <Style
    x:Key="CustomButtonStyle" TargetType="{x:Type local:CustomButton}">
    <Setter Property="FontSize" Value="18" /> <!--Override the font size -->
    <Setter Property="FontWeight" Value="Bold" />
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type local:CustomButton}">
                <Button Style="{StaticResource ButtonStyleBase}" 
                    Height="{TemplateBinding Height}" 
                        Command="{Binding RelativeSource={RelativeSource AncestorType={x:Type local:CustomButton}}, Path=Command}"
                        CommandParameter="{Binding}"
                        Width="{TemplateBinding Width}">
                    <Grid>
                        <StackPanel>
                            <Image Source="Image/icon.jpg" />
                            <TextBlock Text="{TemplateBinding Text}"></TextBlock>
                        </StackPanel>
                    </Grid>
                </Button>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

请注意,我们想要继承模板的按钮被包裹在我的新模板中,并且样式设置为现有的按钮。对于复选框,也要采用同样的方式,并在CustomCheckBox的新ControlTemplate中垂直地组织复选框和标签。

恐怕不行。如果您想将控件定义为UserControl(我的意思是带有代码后台),而不是CustomControl,那么在任何情况下都必须继承自按钮或模板基于的控件。否则,当应用ButtonBaseStyle时,您将会遇到编译错误。但我会尝试并告诉您。 - Oliamster
很不幸,如果有一种方法的话那就太好了。如果可能的话,UserControl应该被视为我们在代码后台继承的基础。 - Hawkeye4040
1
这是我见过的最好的解决方案之一。保持默认按钮样式和行为非常实用。无需处理动画、触发器和状态。 - aliassce

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接