Pregunta Objetos vinculantes definidos en código subyacente


Tengo un objeto que se crea una instancia en código detrás, por ejemplo, el XAML se llama window.xaml y dentro de window.xaml.cs

protected Dictionary<string, myClass> myDictionary;

¿Cómo puedo vincular este objeto a, por ejemplo, una vista de lista, usando solo marcas de XAML?

Actualizar:

(Esto es exactamente lo que tengo en mi código de prueba):

<Window x:Class="QuizBee.Host.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="{Binding windowname}" Height="300" Width="300"
    DataContext="{Binding RelativeSource={RelativeSource Self}}">
    <Grid>
    </Grid>
</Window>

Y en código subyacente

public partial class Window1 : Window
{
    public const string windowname = "ABCDEFG";

    public Window1()
    {
        InitializeComponent();
    }
}

Supongamos que el título debe convertirse en "ABCDEFG" ¿verdad? pero termina mostrando nada.


73
2017-11-10 02:39


origen


Respuestas:


Puede configurar DataContext para su control, formulario, etc. de la siguiente manera:

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

Aclaración:

El contexto de datos que se establece en el valor anterior se debe hacer en cualquier elemento "propietario" del código subyacente, por lo que para una ventana, debe establecerlo en la declaración de ventana.

Tengo tu ejemplo trabajando con este código:

<Window x:Class="MyClass"
  Title="{Binding windowname}"
  DataContext="{Binding RelativeSource={RelativeSource Self}}"
  Height="470" Width="626">

El DataContext establecido en este nivel es heredado por cualquier elemento de la ventana (a menos que lo cambies explícitamente por un elemento hijo), así que después de configurar el DataContext para la ventana, deberías poder hacer un enlace directo a CodeBehind propiedades desde cualquier control en la ventana.


88
2017-11-10 02:47



Hay una forma mucho más fácil de hacer esto. Puede asignar un nombre a su ventana o UserControl, y luego vincular por ElementName.

Window1.xaml

<Window x:Class="QuizBee.Host.Window1"
        x:Name="Window1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

    <ListView ItemsSource="{Binding ElementName=Window1, Path=myDictionary}" />
</Window>

Window1.xaml.cs

public partial class Window1:Window
{
    // the property must be public, and it must have a getter & setter
    public Dictionary<string, myClass> myDictionary { get; set; }

    public Window1()
    {
        // define the dictionary items in the constructor
        // do the defining BEFORE the InitializeComponent();

        myDictionary = new Dictionary<string, myClass>()
        {
            {"item 1", new myClass(1)},
            {"item 2", new myClass(2)},
            {"item 3", new myClass(3)},
            {"item 4", new myClass(4)},
            {"item 5", new myClass(5)},
        }; 

        InitializeComponent();
    }
}

109
2018-05-16 20:07



Si bien la respuesta de Guy es correcta (y probablemente se ajusta a 9 de cada 10 casos), vale la pena señalar que si intenta hacer esto desde un control que ya tiene su DataContext configurado más arriba en la pila, lo restablecerá cuando configure DataContext volver a sí mismo:

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

Esto, por supuesto, romperá tus enlaces existentes.

Si este es el caso, debe establecer RelativeSource en el control que está intentando vincular, en lugar de su padre.

es decir, para vincular las propiedades de un UserControl:

Binding Path=PropertyName, 
        RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}

Dado lo difícil que puede ser actualmente ver qué está pasando con el enlace de datos, vale la pena tener esto en cuenta incluso si encuentra esa configuración RelativeSource={RelativeSource Self} actualmente funciona :)


22
2018-05-11 15:09



Solo un poco más de aclaración: Una propiedad sin 'get', 'set' no podrá ser enlazada

Estoy enfrentando el caso al igual que el caso del asesino. Y debo tener las siguientes cosas para que el enlace funcione correctamente:

//(1) Declare a property with 'get','set' in code behind
public partial class my_class:Window {
  public String My_Property { get; set; }
  ...

//(2) Initialise the property in constructor of code behind
public partial class my_class:Window {
  ...
  public my_class() {
     My_Property = "my-string-value";
     InitializeComponent();
  }

//(3) Set data context in window xaml and specify a binding
<Window ...
DataContext="{Binding RelativeSource={RelativeSource Self}}">
  <TextBlock Text="{Binding My_Property}"/>
</Window>

4
2017-09-30 06:21



Definir un convertidor:

public class RowIndexConverter : IValueConverter
{
    public object Convert( object value, Type targetType,
                           object parameter, CultureInfo culture )
    {
        var row = (IDictionary<string, object>) value;
        var key = (string) parameter;
        return row.Keys.Contains( key ) ? row[ key ] : null;
    }

    public object ConvertBack( object value, Type targetType,
                               object parameter, CultureInfo culture )
    {
        throw new NotImplementedException( );
    }
}

Enlace a una definición personalizada de un diccionario. Hay muchas anulaciones que he omitido, pero el indexador es el más importante, porque emite el evento de propiedad cambiada cuando se cambia el valor. Esto es obligatorio para el enlace de origen a destino.

public class BindableRow : INotifyPropertyChanged, IDictionary<string, object>
{
    private Dictionary<string, object> _data = new Dictionary<string, object>( );

    public object Dummy   // Provides a dummy property for the column to bind to
    {
        get
        {
            return this;
        }
        set
        {
            var o = value;
        }
    }


    public object this[ string index ]
    {
        get
        {
            return _data[ index ];
        }
        set
        {
            _data[ index ] = value;
            InvokePropertyChanged( new PropertyChangedEventArgs( "Dummy" ) ); // Trigger update
        }
    }


}

En su archivo .xaml use este convertidor. Primera referencia:

<UserControl.Resources>
    <ViewModelHelpers:RowIndexConverter x:Key="RowIndexConverter"/>
</UserControl.Resources>

Entonces, por ejemplo, si su diccionario tiene una entrada donde la clave es "Nombre", entonces para vincularse a ella: use

<TextBlock  Text="{Binding Dummy, Converter={StaticResource RowIndexConverter}, ConverterParameter=Name}">

1
2017-11-10 03:07



Haga que su propiedad "windowname" sea DependencyProperty y conserve el resto.


1
2017-11-10 07:42



En su código, establezca el DataContext de la ventana en el diccionario. En tu XAML, puedes escribir:

<ListView ItemsSource="{Binding}" />

Esto vinculará el ListView al diccionario.

Para escenarios más complejos, esto sería un subconjunto de técnicas detrás del MVVM patrón.


0
2017-11-10 02:44