Подтвердить что ты не робот

В WPF почему не работает TemplateBinding, где работает Binding?

Хорошо... это оставляет меня почесывать мою голову. У меня есть два элемента управления 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 я хочу связать свойство CustomFoo Text как источник внутреннего свойства UserFoo Text. Обычно это легко. Вы просто устанавливаете свойство TextFoo для текста "{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}"

Итак, что дает? Что мне не хватает?

4b9b3361

Ответ 1

Нашел этот пост на форуме 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

Ответ 2

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

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

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