2010-10-01 13 views
42

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.Enlace a Self/'esto' en XAML

En el código, esto es muy fácil - en el constructor de la ventana, añadí 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 denominado 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

Respuesta

66

En primer lugar utilizar una coma entre el RelativeSource y la ruta en su Encuadernación:

<Button x:Name="button1" Width="{Binding RelativeSource={RelativeSource Self}, 
           Path=ButtonWidth}"/> 

En segundo lugar, la RelativeSource se une al botón. El botón no tiene una propiedad llamada ButtonWidth. Supongo que debes unirme al control de tus padres.

Así que trate de este RelativeSource vinculante:

<Button x:Name="button1" Width="{Binding RelativeSource= 
    {RelativeSource FindAncestor, AncestorType={x:Type YourNamespace:YourParentControl}}, 
    Path=ButtonWidth}"/> 
+0

Muchas gracias por esta publicación. ¡Me ayudó mucho! He estado buscando una buena solución 3 horas ahora. –

+0

Tengo un DataGrid donde si el usuario accede a uno de sus Comandos de MenuItem de ContextMenu en línea a través de un KeyBinding de InputBinding cuyo CommandParameter = "{Binding ElementName = MyDataGrid, Path = SelectedItems}", pasará los SelectedItems al Bound ICommand. Sin embargo, se pasa null si se accede a través de ContextMenu. He intentado CommandParameter = "{Binding SelectedItems}", "{Binding ElementName = MyDataGrid, Path = SelectedItems}", "{Binding RelativeSource = {RelativeSource FindAncestor, AncestorType = {x: Type DataGrid}}, Path = SelectedItems}" . Establecí CommandParameter antes del comando. – Tom

26

Una forma I Get Around tener que lidiar con RelativeSource y similares es nombrar el elemento XAML raíz:

<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 establecer el DataContext también podría 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> 

Me parece un buen truco para no tener que reme mber todas las complejidades del enlace RelativeSource.

23

Creo que lo que busca es la siguiente:

<Window x:Class = "blah blah all the regular stuff" 

DataContext="{Binding RelativeSource={RelativeSource Self}}" 

> 
+0

Verificado todavía funciona en la aplicación Windows 10 en el elemento principal . – Lavamantis

3

El problema de nombrar el elemento XAML raíz es que, si usted entra en el hábito de usar el mismo nombre (es decir, "_Es", "Root", etc.) para todas las raíces de su proyecto, luego el enlace tardío en plantillas anidadas puede acceder al elemento incorrecto. Esto se debe a que, cuando se utiliza {Binding}ElementName=... en un Template, los nombres se resuelven en tiempo de ejecución subiendo el árbol NameScope hasta encontrar 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 el acceso ya no es necesario, ese {Binding} se convertirá en desorden: la responsabilidad del acceso pertenece correctamente con el destino y el enlace.

En consecuencia, aquí es un simple extensión de marcado 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:

enter image description here


n.b.

para mayor claridad, sin clr-namespace se utiliza, pero tenga en cuenta que el XAML que se muestra aquí funciona realmente para acceder al espacio de nombres global (aunque el diseñador VS2013 se queja)

0

Desafortunadamente, nombrando 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, p.

<UserControl x:Class="Path.MyClass" x:Name="internalName"> 
    <Border Background={Binding Path=Background, ElementName=internalName}" ... 

entonces

<Page> 
    <local:MyClass x:Name=externalName /> 

</Page> 

BTW, Windows 10 ha corregido un error (presente al de Windows 8.1), cuando se utiliza mismo nombre interno para diferentes elementos en mismo diseño.

Aún así, preferiría usar {RelativeSource Self}, ya que parece más lógico y más seguro para mí.

Cuestiones relacionadas