c# - español - Encuadernación a sí mismo/''esto'' en XAML
xaml tutorial (5)
Creo que lo que estás buscando es esto:
<Window x:Class = "blah blah all the regular stuff"
DataContext="{Binding RelativeSource={RelativeSource Self}}"
>
Pregunta simple de WPF / XAML. En XAML, ¿cómo hago referencia al objeto Self / this en un contexto dado? En una aplicación muy básica con una ventana principal, un control y una propiedad codificada C # de la ventana, quiero vincular una propiedad del control a la propiedad codificada a mano de la ventana.
En el código, esto es muy fácil: en el constructor de la ventana, agregué esto:
Binding bind = new Binding();
bind.Source = this;
bind.Path = new PropertyPath("ButtonWidth");
button1.SetBinding(WidthProperty, bind);
Obviamente, tengo una propiedad llamada ButtonWidth, y un control llamado button1. No puedo entender cómo hacer esto en XAML. Varios intentos como el siguiente ejemplo no han funcionado:
<Button x:Name="button1" Width="{Binding Source=Self Path=ButtonWidth}"/>
<Button x:Name="button1" Width="{Binding RelativeSource={RelativeSource Self} Path=ButtonWidth}"/>
etc
Gracias
Desafortunadamente, nombrar el elemento raíz con "ElementName = .." parece ser la única forma con UWP ya que {RelativeSource Self} no es compatible allí.
Por extraño que parezca, esto todavía funciona cuando el nombre es superior en el diseño, por ejemplo
<UserControl x:Class="Path.MyClass" x:Name="internalName">
<Border Background={Binding Path=Background, ElementName=internalName}" ...
entonces
<Page>
<local:MyClass x:Name=externalName />
</Page>
Por cierto, Windows 10 solucionó un error (presente en Windows 8.1), cuando se usa el mismo nombre interno para diferentes elementos en el mismo diseño.
Aún así, preferiría usar {RelativeSource Self}, ya que parece más lógico y más seguro para mí.
El problema con el nombre del elemento raíz XAML
es que, si adquiere el hábito de usar el mismo nombre (es decir, "_this", "Root", etc.) para todas las raíces de su proyecto, entonces el enlace final en anidado las plantillas pueden acceder al elemento incorrecto. Esto se debe a que, cuando se usa {Binding}
ElementName=...
en una Template
, los nombres se resuelven en tiempo de ejecución subiendo el árbol NameScope
hasta que se encuentra la primera coincidencia.
La solución de Clint evita nombrar el elemento raíz, pero establece el elemento raíz en su propio DataContext
, que podría no ser una opción si el DataContext es necesario para, por ejemplo, datos. También parece un poco torpe introducir otro enlace en un elemento con el único fin de proporcionar acceso a él. Más tarde, si ya no se necesita acceso, ese {Binding}
se convertirá en desorden: la responsabilidad del acceso pertenece correctamente al objetivo y al enlace.
En consecuencia, aquí hay una extensión de marcado simple para acceder al elemento raíz XAML sin nombrarlo:
using System.Xaml;
using System.Windows.Markup;
public sealed class XamlRootExtension : MarkupExtension
{
public override Object ProvideValue(IServiceProvider sp)
{
var rop = sp.GetService(typeof(IRootObjectProvider)) as IRootObjectProvider;
return rop == null ? null : rop.RootObject;
}
};
XAML:
<Window x:Class="MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:global="clr-namespace:">
<TextBlock Text="{Binding Source={global:XamlRoot},Mode=OneTime}" />
</Window>
Resultado:
nótese bien
para mayor claridad, no se usa clr-namespace
, pero tenga en cuenta que el XAML que se muestra aquí realmente funciona para acceder al espacio de nombres global
(aunque el diseñador de VS2013 se queja)
Primero use una coma entre RelativeSource y Path en su enlace:
<Button x:Name="button1" Width="{Binding RelativeSource={RelativeSource Self},
Path=ButtonWidth}"/>
En segundo lugar, RelativeSource se une al botón. El botón no tiene una propiedad llamada ButtonWidth. Supongo que debes unirme al control de tus padres.
Por lo tanto, intente este enlace RelativeSource:
<Button x:Name="button1" Width="{Binding RelativeSource=
{RelativeSource FindAncestor, AncestorType={x:Type YourNamespace:YourParentControl}},
Path=ButtonWidth}"/>
Una de las maneras en que me las ingenio para lidiar con RelativeSource es creando un nombre para el elemento raíz XAML:
<Window x:Class="TestApp2.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525"
x:Name="_this"
>
<Grid>
<Button x:Name="button" Width="{Binding ElementName=_this,Path=ButtonWidth}" />
</Grid>
</Window>
Si desea configurar DataContext, también puede hacer esto:
<Window x:Class="TestApp2.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525"
x:Name="_this"
>
<Grid DataContext="{Binding ElementName=_this}">
<Button x:Name="button" Width="{Binding Path=ButtonWidth}" />
</Grid>
</Window>
Encuentro que es un buen truco para no tener que recordar todas las complejidades del enlace de RelativeSource.