В WPF почему TemplateBinding не работает там, где Binding работает? - PullRequest
39 голосов
/ 06 мая 2011

Хорошо ... это заставляет меня чесать голову. У меня есть два элемента управления WPF - один пользовательский элемент управления, а другой пользовательский элемент управления. Давайте назовем их UserFoo и CustomFoo. В шаблоне элемента управления для CustomFoo я использую экземпляр UserFoo, который является именованной частью, чтобы я мог добраться до него после применения шаблона. Это отлично работает.

Теперь и для UserFoo, и для CustomFoo определено свойство Text (независимо, т. Е. Не общий DP, использующий AddOwner. Не спрашивайте ...), которые оба объявлены следующим образом ...

public static readonly DependencyProperty TextProperty = DependencyProperty.Register(
    "Text",
    typeof(string),
    typeof(UserFoo), // The other is CustomFoo
    new FrameworkPropertyMetadata(
        null,
        FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
        null,
        null,
        true,
        UpdateSourceTrigger.PropertyChanged
    )
);

Обратите особое внимание, что режим установлен на TwoWay, а UpdateSourceTrigger установлен на PropertyChanged, опять же для обоих.

Итак, в шаблоне стиля для CustomFoo я хочу связать свойство Text CustomFoo как источник с внутренним свойством Text UserFoo. Обычно это легко. Вы просто устанавливаете текстовое свойство UserFoo на "{TemplateBinding Text}", но по какой-то причине оно идет только в одну сторону (т.е. UserFoo правильно настроен из CustomFoo, но не наоборот), хотя опять же, оба DP установлены для двустороннего! Тем не менее, при использовании относительной исходной привязки вместо привязки шаблона, она прекрасно работает! Эм ... что ??

// This one works
Text="{Binding Text, RelativeSource={RelativeSource AncestorType={local:CustomFoo}}, Mode=TwoWay}"

// As does this too...
Text="{Binding Text, RelativeSource={RelativeSource TemplatedParent}, Mode=TwoWay}"

// But not this one!
Text="{TemplateBinding Text}"

Так что дает? Чего мне не хватает?

Ответы [ 2 ]

51 голосов
/ 06 мая 2011

Найден этот пост на форуме MSDN: http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/0bb3858c-30d6-4c3d-93bd-35ad0bb36bb4/

Это говорит это:

TemplateBinding - это оптимизированная форма Binding для шаблонных сценариев, аналогичная Binding, созданной с

{Binding RelativeSource={RelativeSource TemplatedParent}}

Примечание от OP: Вопреки тому, что говорится в документации, на самом деле, это должно быть так ...

{Binding RelativeSource={RelativeSource TemplatedParent}, Mode=OneWay}

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

TemplateBinding передает данные из шаблонного родителя в свойство, к которому привязан шаблон. Если вам нужно передать данные в противоположном направлении или в обоих направлениях, создайте привязку с RelativeSource для TemplatedParent со свойством Mode, установленным в OneWayToSource или TwoWay.

Подробнее в: http://msdn.microsoft.com/en-us/library/ms742882.aspx

Похоже, Mode = OneWay является одной из «оптимизаций» использования TemplateBinding

10 голосов
/ 06 мая 2011

TemplateBinding не поддерживает двустороннюю привязку, это делает только Binding.Даже с вашим параметром BindsTwoWayBeDefault он не будет поддерживать двустороннюю привязку.

Более подробную информацию можно найти здесь , но в итоге:

Однако,TemplateBinding может передавать данные только в одном направлении: от шаблонного родителя к элементу с TemplateBinding.Если вам нужно передать данные в противоположном направлении или обоими способами, то Binding with RelativeSource of TemplatedParent - ваш единственный вариант.Например, взаимодействие с TextBox или Slider внутри шаблона приведет к изменению свойства только у шаблонного родителя, если вы используете двустороннюю привязку.

...