it-swarm-eu.dev

Liaison d'objets définis dans code-behind

J'ai un objet qui est instancié dans le code derrière, par exemple, le XAML s'appelle window.xaml et dans le window.xaml.cs

protected Dictionary<string, myClass> myDictionary;

Comment puis-je lier cet objet à, par exemple, une vue de liste, en utilisant uniquement des balises XAML?

Mettre à jour:

(C'est exactement ce que j'ai dans mon code de test):

<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>

Et dans codebehind

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

    public Window1()
    {
        InitializeComponent();
    }
}

Supposons que le titre devienne "ABCDEFG", non? mais ça finit par ne rien montrer.

76
xandy

Vous pouvez définir le DataContext pour votre contrôle, formulaire, etc. comme suit:

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

Clarification :

Le contexte de données défini sur la valeur ci-dessus doit être défini à l'élément quel que soit "le propriétaire" du code situé derrière. Par conséquent, pour une fenêtre, vous devez le définir dans la déclaration Window.

J'ai votre exemple de travail avec ce code:

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

Le DataContext défini à ce niveau est ensuite hérité par n'importe quel élément de la fenêtre (à moins que vous ne le changiez explicitement pour un élément enfant). Ainsi, après avoir défini le DataContext pour la fenêtre, vous devriez pouvoir faire une liaison directe à CodeBehind properties de tout contrôle sur la fenêtre.

93
Guy Starbuck

Il y a un moyen beaucoup plus facile de faire cela. Vous pouvez attribuer un nom à votre fenêtre ou à votre contrôle utilisateur, puis lier par 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();
    }
}
116
Saad Imran.

Bien que la réponse de Guy soit correcte (et qu'elle corresponde probablement à 9 cas sur 10), il convient de noter que si vous essayez d'effectuer cette opération à partir d'un contrôle dont le DataContext est déjà placé plus haut dans la pile, vous devrez le réinitialiser lorsque vous définissez DataContext retour à lui-même:

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

Ce sera bien sûr alors casser vos liaisons existantes.

Si tel est le cas, vous devez définir RelativeSource sur le contrôle que vous essayez de lier, plutôt que sur son parent.

c'est-à-dire pour la liaison aux propriétés d'un UserControl:

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

Étant donné la difficulté actuelle de voir ce qui se passe avec la liaison de données, gardez cela à l'esprit même si vous trouvez que le paramètre RelativeSource={RelativeSource Self} fonctionne actuellement :)

23
CatBusStop

Juste un peu plus de précision: Une propriété sans 'get', 'set' ne pourra pas être liée

Je fais face à l'affaire, tout comme le cas du demandeur. Et je dois avoir les choses suivantes pour que la reliure fonctionne correctement:

//(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>
5
jondinham

Définir un convertisseur:

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( );
    }
}

Lier à une définition personnalisée d'un dictionnaire. J'ai omis de nombreuses substitutions, mais l'indexeur est l'important, car il émet l'événement property modified lorsque la valeur est modifiée. Ceci est requis pour que la source cible la liaison.

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
        }
    }


}

Dans votre fichier .xaml, utilisez ce convertisseur. Première référence:

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

Ensuite, par exemple, si votre dictionnaire a une entrée où la clé est "Nom", alors pour vous y connecter: utilisez

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

Faites de votre propriété "windowname" un DependencyProperty et conservez le même.

1
viky

J'avais exactement le même problème mais le mien ne l'était pas parce que je définissais une variable locale ... J'étais dans une fenêtre enfant et je devais définir un DataContext relatif que je venais d'ajouter au Window XAML.

<Window x:Class="Log4Net_Viewer.LogItemWindow"
    xmlns="http://schemas.Microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.Microsoft.com/winfx/2006/xaml"
    DataContext="{Binding RelativeSource={RelativeSource Self}}"
    Title="LogItemWindow" Height="397" Width="572">
0
davesbrain

Dans votre code derrière, définissez le DataContext de la fenêtre sur le dictionnaire. Dans votre XAML, vous pouvez écrire:

<ListView ItemsSource="{Binding}" />

Cela liera le ListView au dictionnaire.

Pour des scénarios plus complexes, il s'agirait d'un sous-ensemble de techniques derrière le modèle MVVM

0
Szymon Rozga

Une solution serait de créer un ObservableCollection (System.Collections.ObjectModel) et d’y avoir les données de votre dictionnaire. Ensuite, vous devriez pouvoir lier ObservableCollection à votre ListBox.

Dans votre XAML, vous devriez avoir quelque chose comme ça:

<ListBox ItemsSource="{Binding Path=Name_of_your_ObservableCollection" />
0
Partial

Vous pouvez essayer x: astuce de référence

<Window ... x:Name="myWindow"><ListBox ItemsSource="{Binding Items, Source={x:Reference myWindow}}" /></Window>