2009-04-15 6 views
0

Un peu d'histoire: Je suis en train de charger une interface utilisateur WPF à partir d'une base de données qui sont stockées dans une table de propriétés (type de contrôle, l'étiquette, la marge, etc.) que je charge dans une classe que j'appelle ControlPresenter. Fondamentalement, je définis ControlPresenter en tant que DataContext d'un ContentPresenter et utiliser un TemplateSelector pour choisir le type de contrôle à charger. Les DataTemplate (s) chargent leurs propriétés hors des DependencyProperties exposées par le ControlPresenter.Comment puis-je implémenter un DataBinding "pass-through"?

Tout cela fonctionne très bien. Le problème auquel je suis confronté vient lorsque j'essaie de lier des données (par exemple la propriété Text de TextBox à la propriété Name d'un présentateur) dans d'autres présentateurs (qui ont des propriétés normales qui implémentent INotifyPropertyChanged) à ces contrôles. DataContext est le ControlPresenter associé au contrôle de sorte que je ne peut pas se lier directement aux autres témoins et je ne peux pas mettre en place deux fixations sur la même propriété de dépendance (I ne peut pas lier le contrôle et la propriété présentateur souhaitée à la même DP) .

solutions possibles:

  1. je pourrais convertir tous les autres présentateurs à utiliser DPs (temps extrêmement long et susceptibles de causer des problèmes avec l'héritage)
  2. je pourrais utiliser deux DPs pour chaque propriété I veulent passer à travers et essayer de les attacher ensemble au moyen de notifications modifiées

ces deux semblent problématiques et sujettes à la rupture, donc je suis en espérant que quelqu'un d'autre est venu avec un meilleur s solution.

Editer: Je suis arrivé avec une solution qui fonctionne assez bien (voir ci-dessous). Merci à tous ceux qui ont regardé cela et si vous trouvez une meilleure méthode que je l'ai fait s'il vous plaît faites le moi savoir.

Répondre

0

J'ai fini par définir les liaisons dans le code en définissant Binding.Source sur le ViewModel souhaité et en utilisant le chemin dans la base de données pour Binding.Path.Je stocke les liaisons dans un dictionnaire (Of DependencyProperty, BindingBase) et lorsque le contrôle charge, j'utilise BindingOperations.SetBinding pour définir les liaisons sur le contrôle. Cela semble fonctionner plutôt bien sauf pour des problèmes d'ordre d'opérations occasionnels (par exemple, si vous définissez SelectedItem/SelectedValue avant le ItemsSource, il sera défini mais ne s'affichera pas dans un ComboBox).

0

Il existe plusieurs façons d'accéder à des DataContexts de portée.

1) ElementName Reliure

Ceci est probablement le moins utile que, dans la plupart des scénarios du monde réel, ce que vous essayez de se lier à est hors de NameScope de toute façon. Mais c'est un moyen d'accéder à un contexte de données parallèle ou parent tant que l'élément de cadre est dans la portée de nom.

<TextBox Text="{Binding ElementName=ControlSomewhereElseBoundToSomeOtherControlPresenter, Path=DataContext.SomeTextPropertyOnTheControlPresenter}" /> 

2) RelativeSource Reliure

Ceci est similaire à # 1 mais en utilisant RelativeSource pour accéder à l'élément visuel approprié et saisir le DataContext. Bien sûr, cela suppose que le DataContext que vous essayez d'obtenir est ABOVE où vous vous trouvez actuellement dans l'arborescence Visual.

3) Utilisez un relais statique

Vous pouvez exposer vos ControlPresenters alternatives au sein d'une classe statique qui agit comme une façade à votre ViewModel. Ensuite, dans chaque propriété d'instance de construction ViewModel, les propriétés qui passent aux méthodes/propriétés statiques. C'est un moyen courant d'obtenir du stockage partagé sur plusieurs modèles View. Je me rends compte que cette technique vous obligerait à modifier votre modèle un peu, mais ajouter un simple wrapper ViewModel autour de ces classes "ControlPresenter" semble beaucoup plus simple que les options que vous avez décrites.

+0

hmm, je vais devoir voir si je peux obtenir l'option numéro 3 fonctionnant. –