web-dev-qa-db-fra.com

Lier WPF au membre de classe dans le code derrière

Question assez simple, mais ne semble pas trouver une réponse complète ici ...

J'ai besoin de lier des données dans xaml à une propriété d'un membre de classe dans codebehind.

<Window x:Class="Main">
    <customcontrol Name="View" IsChecked="{Binding ElementName=RecordProp, Path=IsViewChecked}" />
...

À quoi ressemble le code derrière:

class Main 
{    
    ...
    private Record _record;
    public Record RecordProp
    {
      get { return _record; }
    }
    ...
}


class Record
{
  public bool IsViewChecked
  {
    get; set;
  }
}

Ce que j'ai maintenant ne fonctionne pas, qu'est-ce que je fais mal?

30
jaws

Le chemin a besoin d'une source pour aller contre (Source, DataContext, RelativeSource, ElementName). ElementName ne peut être utilisé que pour faire référence aux éléments déclarés en XAML par leur x: Name. Essayez plutôt de pointer vers votre fenêtre comme source:

IsChecked="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Window}}, Path=RecordProp.IsViewChecked}"
27
John Bowen

Ce que je vois ici, c'est que le nom de classe de votre fenêtre est Main, que vous y avez ajouté une propriété RecordProp et que vous essayez maintenant de vous lier à IsChecked propriété de l'élément nommé RecordProp. Je pense que vous êtes un peu confus sur la façon dont les noms fonctionnent.

Ajout du x:Name l'attribut à un élément XAML crée un champ dans la classe window avec ce nom. Cela vous permet de référencer des éléments nommés dans votre code, et cela vous a probablement amené à penser que la liaison peut faire la même chose.

Mais ce n'est pas ainsi que la liaison trouve des éléments nommés. Le x:Name attribute prend également l'objet créé par l'élément XAML et l'enregistre sous ce nom dans la portée de la fenêtre. (Voir article de MSDN sur les étendues de noms XAML. ) C'est ce que la liaison examine pour résoudre les noms d'élément. Étant donné que vous n'ajoutez jamais l'objet à l'étendue de noms, la définition de la propriété ElementName sur une liaison ne le trouvera pas.

Il y a deux ou trois choses que vous pourriez imaginer faire. Si vous voulez vraiment vous lier à une propriété de la fenêtre, vous pouvez donner un nom à la fenêtre et la lier à la propriété en utilisant un chemin de propriété:

<Window x:Name="MainWindow" x:Class="Main">
...
   <customcontrol Name="View" IsChecked="
                 {Binding ElementName=MainWindow, 
                  Path=RecordProp.IsViewChecked}" />

Encore plus simple est de simplement définir le contexte de données dans le constructeur:

DataContext = this;

Une fois que vous faites cela, vous pouvez simplement vous lier à la propriété RecordProp (et à toute autre propriété de la fenêtre) comme ceci:

<customControl Name="View" IsChecked={Binding RecordProp.IsChecked}/>

Bien sûr, cela ne fonctionnera pas si vous avez besoin que le contexte de données de la fenêtre soit défini sur autre chose.

Une autre possibilité consiste à implémenter la propriété comme ceci:

public Record RecordProp 
{
  get { return (Record)Resources["RecordProp"]; }
  set { Resources["RecordProp"] = value; }
}

Vous pouvez vous y lier en utilisant (par exemple) Binding {DynamicResource RecordProp}, Path=IsChecked". Puisqu'il s'agit d'une ressource dynamique, si quelque chose d'extérieur à la fenêtre définit la propriété RecordProp de la fenêtre, les liaisons vers celle-ci seront actualisées - ce qui ne se produira pas si vous faites simplement de RecordProp une propriété (sauf si vous implémentez une notification de modification).

30
Robert Rossney

Je pense avoir une réponse plus simple que celles qui ont été données jusqu'à présent. Ajoutez simplement ceci à la déclaration de fenêtre (la toute première balise) en XAML:

x:Name="this"

Ensuite, vous pouvez lier des données comme ceci:

<customcontrol Name="View" IsChecked="{Binding ElementName=this, Path=RecordProp.IsViewChecked}" />

J'ai vérifié si C # se plaignait qu'il existe déjà un "ceci", et il ne l'a pas fait, je suppose parce qu'ils se réfèrent tous deux au même objet exact.

C'est la solution que j'ai utilisée lorsque j'ai rencontré le même problème et je l'ai trouvée très intuitive à utiliser.

7
JoeCool

La liaison de données ne fonctionnera pas contre les champs privés. Il est plutôt destiné aux propriétés publiques. Essayez d'exposer la valeur _record publiquement et y lier à la place.

Référence - http://msdn.Microsoft.com/en-us/library/ms743643.aspx

3
JaredPar