访问自定义用户控件的ContentTemplate中的自定义属性

本文关键字:ContentTemplate 自定义属性 控件 自定义 用户 访问 | 更新日期: 2023-09-27 18:16:58

我有以下自定义用户控件:

namespace MyApp.Controls {
    public partial class ArticleButton: UserControl {
        public ArticleButton () {
            InitializeComponent ();
        }
        public static readonly DependencyProperty TitleProperty;
        static ArticleButton () {
            TitleProperty = DependencyProperty.RegisterAttached ("Title", 
                typeof (String), typeof (ArticleButton));
        }
        [Description ("The name of the article."), Category ("Common Properties")]
        public String Title {
            get { return "TEST"; }
        }
    }
}

对应的XAML:

<UserControl x:Class="MyApp.Controls.ArticleButton"
             Name="UC"
             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:MyApp.Controls">
    <Button Name="button" Click="button_Click" Style="{StaticResource defaultButtonStyle}">
        <Button.ContentTemplate>
            <DataTemplate>
                <Grid>
                    <TextBlock Text="{Binding Path=Title, ElementName=UC}" />
                </Grid>
            </DataTemplate>
        </Button.ContentTemplate>
    </Button>
</UserControl>

其中defaultButtonStyleApp.xaml中定义(还有更多,但这应该足够了):

<Style TargetType="Button" x:Key="defaultButtonStyle">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="Button">
                <Border Name="border"
                       BorderThickness="1"
                       Padding="4,2"
                       BorderBrush="DarkGray"
                       CornerRadius="3"
                       Background="{TemplateBinding Background}">
                    <Grid>
                        <ContentPresenter HorizontalAlignment="Center"
                                  VerticalAlignment="Center"/>
                    </Grid>
                </Border>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

我的问题是没有显示属性Title,我尝试了以下也不工作:

<TextBlock Text="{Binding Path=Title, ElementName=UC}" />
<TextBlock Text="{Binding Path=Title, RelativeSource={RelativeSource TemplatedParent}}" />
<TextBlock Text="{Binding Path=Title, RelativeSource={RelativeSource AncestorType={x:Type local:ArticleButton}}}" />

我发现很多帖子有类似的问题,但没有一个帮助…我认为问题是,我试图访问内部按钮的内容模板内的自定义用户控件的自定义属性,但如何做到这一点。

访问自定义用户控件的ContentTemplate中的自定义属性

总结评论你的第3个RelativeSource绑定

<TextBlock Text="RelativeSource={RelativeSource AncestorType={x:Type local:ArticleButton}}"/>

应该工作良好,只是使用Register而不是RegisterAttached。至于其他绑定,{Binding Path=Title, ElementName=UC}不起作用,因为ConrtrolTemplate有自己的名称作用域,{Binding Path=Title, RelativeSource={RelativeSource TemplatedParent}}"不起作用,因为您没有针对Button设置属性,而是针对UserControl

另一个问题是,您针对CLR包装器设置了默认值,并且,正如本MSDN页面所述,CLR包装器被忽略,GetValue/SetValue方法被直接调用TitleProperty

WPF XAML处理器在加载二进制XAML和处理作为依赖属性的属性时使用属性系统方法来处理依赖属性。这有效地绕过了属性包装器。当你实现自定义依赖属性时,你必须考虑到这种行为,并且应该避免在属性包装器中放置除属性系统方法GetValue和SetValue之外的任何其他代码。

如果你想指定默认值和/或属性改变回调,那么当你创建DependencyProperty时,Register方法的另一个变体也接受PropertyMetadata参数,你可以设置这些值。

使用依赖属性时需要注意的另一件事是,因为它的定义是静态的,默认值将在ArticleButton 的所有实例之间共享。所以如果你的类型是list或者其他类你在PropertyMetadata中将其初始化为不同的值那么null相同的实例将作为默认值

共享
public partial class ArticleButton : UserControl
{
    public ArticleButton()
    {
        InitializeComponent();
    }
    public static readonly DependencyProperty TitleProperty =
        DependencyProperty.Register(
            "Title",
            typeof(String),
            typeof(ArticleButton),
            new PropertyMetadata("Test", TitlePropertyChanged));
    private static void TitlePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        (d as ArticleButton).TitlePropertyChanged(e);
    }
    private void TitlePropertyChanged(DependencyPropertyChangedEventArgs e)
    {
        //do something when property changed value
    }
    public String Title
    {
        get { return (string)GetValue(TitleProperty); }
        set { SetValue(TitleProperty, value); }
    }
}