覆盖 XAML 中的控件模板属性

Posted

技术标签:

【中文标题】覆盖 XAML 中的控件模板属性【英文标题】:override control template property in XAML 【发布时间】:2015-09-07 19:36:24 【问题描述】:

如果我在 generic.xaml 中定义了以下 XAML

<Style TargetType="x:Type TextBox">
    <Setter Property="SnapsToDevicePixels" Value="True" />
    <Setter Property="CaretBrush" Value="StaticResource TextBoxCaretBrush" />
    <Setter Property="OverridesDefaultStyle" Value="True" />
    <Setter Property="KeyboardNavigation.TabNavigation" Value="None" />
    <Setter Property="FocusVisualStyle" Value="x:Null" />
    <Setter Property="MinWidth" Value="120" />
    <Setter Property="MinHeight" Value="20" />
    <Setter Property="AllowDrop" Value="True" />
    <Setter Property="Foreground" Value="StaticResource TextBoxTextBrush" />
    <Setter Property="Padding" Value="5,3,0,5" />
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="x:Type TextBoxBase">
                <Border x:Name="Border" CornerRadius="5" Padding="2" BorderThickness="1">
                    <Border.Background>
                        <SolidColorBrush Color="StaticResource TextBoxBackgroundColor" />
                    </Border.Background>
                    <Border.BorderBrush>
                        <SolidColorBrush Color="StaticResource TextBoxBorderColor" />
                    </Border.BorderBrush>
                    <VisualStateManager.VisualStateGroups>
                        <VisualStateGroup x:Name="CommonStates">
                            <VisualState x:Name="Normal" />
                            <VisualState x:Name="Disabled">
                                <Storyboard>
                                    <ColorAnimationUsingKeyFrames Storyboard.TargetName="Border" Storyboard.TargetProperty="(Panel.Background).(SolidColorBrush.Color)">
                                        <EasingColorKeyFrame KeyTime="0" Value="StaticResource DisabledControlLightColor" />
                                    </ColorAnimationUsingKeyFrames>
                                </Storyboard>
                            </VisualState>
                            <VisualState x:Name="ReadOnly">
                                <Storyboard>
                                    <ColorAnimationUsingKeyFrames Storyboard.TargetName="Border" Storyboard.TargetProperty="(Panel.Background).(SolidColorBrush.Color)">
                                        <EasingColorKeyFrame KeyTime="0" Value="StaticResource DisabledControlDarkColor" />
                                    </ColorAnimationUsingKeyFrames>
                                </Storyboard>
                            </VisualState>
                            <VisualState x:Name="MouseOver" />
                        </VisualStateGroup>
                    </VisualStateManager.VisualStateGroups>
                    <ScrollViewer Margin="0" x:Name="PART_ContentHost" />
                </Border>
                <ControlTemplate.Triggers>
                    <Trigger Property="IsFocused" Value="True">
                        <Setter Property="BorderBrush" TargetName="Border" Value="StaticResource TextBoxBorderSelectedBrush" />
                        <Setter Property="Effect">
                            <Setter.Value>
                                <DropShadowEffect ShadowDepth="0" Color="StaticResource HighlightColor" Opacity="1" BlurRadius="5" />
                            </Setter.Value>
                        </Setter>
                        <Setter Property="BorderThickness" Value="2" />
                    </Trigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

在我看来,我已经定义了以下 XAML 以使用上述样式显示 TextBox。

<TextBox Name="UserName" attachedProperties:KeyboardNavigationExt.TabOnEnter="True" Grid.Row="1" KeyboardNavigation.TabIndex="1" Grid.Column="2" Grid.ColumnSpan="3" cal:Message.Attach="[Event TextChanged] = [Action CanLogin]" />

这会在视图上显示一个 TextBox,Template 中的 Border 上的 CornerRadius 为 5。

现在我的问题是,我有一个场景,其中有两个 TextBox 彼此相邻,我想为两个 TextBox 指定CornerRadius,如下所示。

<TextBox Name="UserName" CornerRadius="5,5,0,0" attachedProperties:KeyboardNavigationExt.TabOnEnter="True" Grid.Row="1" KeyboardNavigation.TabIndex="1" Grid.Column="2" Grid.ColumnSpan="3" cal:Message.Attach="[Event TextChanged] = [Action CanLogin]" />

但是 TextBox 没有 CornerRadius 我该如何实现这一点,以便我能够在视图 XAML 中更改 BorderCornerRadius

【问题讨论】:

创建另一个附加属性(代理),就像您对KeyboardNavigationExt.TabOnEnter 所做的那样,但这是CornerRadius 类型的一个,在Style 中设置默认值,并在模板中将ConrnerRadius 绑定到该属性TemplatedParent 的附加属性。像这样,您将能够更改每个 TextBox 的值。检查this答案 如何在模板中绑定它?我试过CornerRadius="TemplateBinding CornerRadius",但我得到一个错误 查看之前评论中答案的链接。你使用RelativeSourceTemplatedParent 绑定 谢谢,这就是我遗漏的一点,我完全错过了您上面评论中的链接,如果您添加您的答案,那么我可以标记为答案 【参考方案1】:

正如评论中提到的,您需要可以针对TextBox 设置的代理属性并在模板中绑定。所以创建AttachedProprtyCornerRadius 类型

public static class AttachedProperties

    public static readonly DependencyProperty CornerRadiusProperty = DependencyProperty.RegisterAttached("CornerRadius", typeof(CornerRadius), typeof(AttachedProperties), new UIPropertyMetadata());

    public static void SetCornerRadius(DependencyObject d, CornerRadius source)
    
        d.SetValue(CornerRadiusProperty, source);
    

    public static CornerRadius GetCornerRadius(DependencyObject d)
    
        return (CornerRadius)d.GetValue(CornerRadiusProperty);
    

更改ControlTemplate 并绑定到TemplatedParent 的该属性

<ControlTemplate TargetType="x:Type TextBox">
    <Border CornerRadius="Binding RelativeSource=RelativeSource TemplatedParent, Path=(local:AttachedProperties.CornerRadius)"/>
</ControlTemplate>

使用默认值将Setter 添加到您的Style

<Setter Property="local:AttachedProperties.CornerRadius" Value="5"/>

然后您可以针对每个 TextBox 手动更改它

<TextBox local:AttachedProperties.CornerRadius="5,5,0,0" .../>

【讨论】:

以上是关于覆盖 XAML 中的控件模板属性的主要内容,如果未能解决你的问题,请参考以下文章

Xamarin XAML语言教程控件模板的模板绑定

Silverlight Xaml 覆盖控件的 IsEnabled 属性

XAML - 如何从 ControlTemplate 中的子项访问父控件的 DataTemplate 属性?

用户控件中的 WPF 将控件模板的内容设置为依赖属性的值

在 Generic.xaml 的模板化控件中应用默认样式

将 XAML 中的可见性绑定到可见性属性