En WPF, ¿por qué no funciona TemplateBinding donde lo hace Binding?
controltemplate propertychanged (2)
Ok ... esto me está dejando rascándome la cabeza. Tengo dos controles WPF: uno es un control de usuario y el otro es un control personalizado. Vamos a llamarlos UserFoo y CustomFoo. En la plantilla de control de CustomFoo, uso una instancia de UserFoo, que es una parte con nombre, así que puedo acceder a ella una vez que se aplica la plantilla. Eso funciona bien
Ahora tanto UserFoo como CustomFoo tienen una propiedad Text
definida en ellos (independientemente, es decir, no es un DP compartido usando AddOwner. No preguntes ...) que son ambos declarados así ...
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
)
);
Observe específicamente que el modo está configurado en TwoWay y UpdateSourceTrigger está establecido en PropertyChanged, nuevamente para ambos.
Por lo tanto, en la plantilla de estilo de CustomFoo, quiero vincular la propiedad Text de CustomFoo como fuente de la propiedad de texto interna del UserFoo. Normalmente, esto es fácil. Simplemente estableces la propiedad de texto de UserFoo en "{TemplateBinding Text}" pero por alguna razón solo va en una dirección (es decir, UserFoo está configurado correctamente desde CustomFoo, pero no al revés), aunque una vez más, ¡ambos DP están configurados para dos direcciones! Sin embargo, cuando se utiliza un enlace de origen relativo en lugar de un enlace de plantilla, ¡funciona muy bien! Um ... ¿qué?
// 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}"
Entonces, ¿qué da? ¿Qué me estoy perdiendo?
Se encontró esta publicación del foro en MSDN: http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/0bb3858c-30d6-4c3d-93bd-35ad0bb36bb4/
Dice esto:
Un TemplateBinding es una forma optimizada de una vinculación para escenarios de plantilla, análoga a un enlace construido con
{Binding RelativeSource={RelativeSource TemplatedParent}}.
Nota de OP: Al contrario de lo que dice en la documentación, en realidad, debería ser esto ...
{Binding RelativeSource={RelativeSource TemplatedParent} Mode=OneWay}.
Archivé una queja en contra de los documentos, y si bien agregaron una oración que ahora indica que siempre son unidireccionales, el ejemplo del código todavía no muestra el modo, pero supongo que es mejor que nada).
TemplateBinding transfiere datos del padre con plantilla a la propiedad que está vinculada a la plantilla. Si necesita transferir datos en la dirección opuesta o en ambos sentidos, cree un Enlace con RelativeSource de TemplatedParent con la propiedad Mode configurada en OneWayToSource o TwoWay.
Más en: http://msdn.microsoft.com/en-us/library/ms742882.aspx
Parece que Mode = OneWay es una de las "optimizaciones" de usar un TemplateBinding
TemplateBinding no es compatible con el enlace bidireccional, solo Binding lo hace. Incluso con su opción BindsTwoWayBeDefault, no será compatible con el enlace bidireccional.
Más información se puede encontrar here , pero para resumir:
Sin embargo, un TemplateBinding solo puede transferir datos en una dirección: desde el elemento primario con plantilla hasta el elemento con TemplateBinding. Si necesita transferir datos en la dirección opuesta o en ambos sentidos, una vinculación con RelativeSource of TemplatedParent es su única opción. Por ejemplo, la interacción con un TextBox o un control deslizante dentro de una plantilla solo cambiará una propiedad en el elemento primario con plantilla si utiliza un enlace bidireccional.