WPF TemplateBinding не работает для каждого свойства

Я создал пользовательский элемент управления, но TemplateBinding не работает для каждого свойства? Привязка шаблона начинает работать, если я использую фиктивный конвертер, который просто пересылает исходные значения. Упрощенный пример с той же проблемой:

<Style TargetType="{x:Type controls:ElipticProgressBar}">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type controls:ElipticProgressBar}">
                <ControlTemplate.Resources>
                    <converters:DebugConverter x:Key="DebugConverter"/>
                </ControlTemplate.Resources>
                <StackPanel>
                    <!--BarColor works always-->
                    <!--BarTickness works-->
                    <Label Background="{TemplateBinding BarColor}" Content="{TemplateBinding BarTickness}"/>
                    <!--BarTickness does not works-->
                    <TextBlock Background="{TemplateBinding BarColor}" Text="{TemplateBinding BarTickness}"/>
                    <!--BarTickness works-->
                    <TextBlock Background="{TemplateBinding BarColor}" Text="{Binding BarTickness, RelativeSource={RelativeSource TemplatedParent}, Mode=OneWay}"/>
                    <!--BarTickness works-->
                    <TextBlock Background="{TemplateBinding BarColor}" Text="{TemplateBinding BarTickness, Converter={StaticResource DebugConverter}}"/>
                </StackPanel>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

обратный код:

public class ElipticProgressBar : Control
{
    static ElipticProgressBar()
    {
        DefaultStyleKeyProperty.OverrideMetadata(typeof(ElipticProgressBar), new FrameworkPropertyMetadata(typeof(ElipticProgressBar)));
    }

    public static readonly DependencyProperty BarTicknessProperty = DependencyProperty.Register(
        "BarTickness", typeof(int), typeof(ElipticProgressBar), new FrameworkPropertyMetadata(default(int)));

    public int BarTickness
    {
        get { return (int)GetValue(BarTicknessProperty); }
        set { SetValue(BarTicknessProperty, value); }
    }

    public static readonly DependencyProperty BarColorProperty = DependencyProperty.Register(
        "BarColor", typeof(Brush), typeof(ElipticProgressBar), new FrameworkPropertyMetadata(default(Brush)));

    public Brush BarColor
    {
        get { return (Brush)GetValue(BarColorProperty); }
        set { SetValue(BarColorProperty, value); }
    }
}

использование:

controls:ElipticProgressBar BarTickness="30" BarColor="Orange"

Отладочный преобразователь:

public class DebugConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return value;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return value;
    }
}

person user007    schedule 04.06.2018    source источник


Ответы (2)


В документах указано, что {TemplateBinding} является

оптимизированная форма привязки для шаблонных сценариев, аналогичная привязке, созданной с помощью {Binding RelativeSource={RelativeSource TemplatedParent}}

с некоторыми ограничениями - самое главное, что работает только внутри визуального дерева!


Что это означает для вашего конкретного случая: пока вы не можете использовать

<TextBlock Text="{TemplateBinding BarTickness}" />

можно (и нужно) использовать

<TextBlock Text="{Binding BarTickness, RelativeSource={RelativeSource TemplatedParent}, Mode=OneWay}" />

потому что свойство TextBlock.Text имеет тип string, а BarTickness — нет.

{TemplateBinding} не выполняет такого преобразования; вот почему вам нужно использовать более общий {Binding} или конвертер, оба метода которого

public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
    return value;
}

public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
    return value;
}

оба преобразуют фактическое значение в object.

person Thomas Flinkow    schedule 04.06.2018

{TemplateBinding} — это оптимизированная версия привязки с некоторыми ограничениями.

В этом случае вам нужно изменить тип свойства BarThickness на string, чтобы иметь возможность напрямую связать его со свойством Text TextBlock с помощью {TemplateBinding}.

person mm8    schedule 04.06.2018