Comment soutenir ListBox SelectedItems liaison avec MVVM dans un navigables application
Je fais une application WPF qui est navigable via personnalisé "Suivant" et "précédent" de boutons et de commandes (c'est à dire non à l'aide d'un NavigationWindow
). Sur un écran, j'ai un ListBox
qui a en charge plusieurs sélections (à l'aide de la Extended
mode). J'ai un modèle d'affichage de cet écran et de stocker les éléments sélectionnés en tant que bien, car ils ont besoin d'être entretenus.
Cependant, je suis conscient que le SelectedItems
propriété d'un ListBox
est en lecture seule. J'ai essayé de contourner le problème en utilisant cette solution ici, mais je n'ai pas été en mesure d'adopter dans ma mise en œuvre. J'ai trouvé que je ne peux pas différencier entre le moment où l'un ou plusieurs des éléments sont désélectionnés et quand j'ai naviguer entre les écrans (NotifyCollectionChangedAction.Remove
est soulevée dans les deux cas, puisque, techniquement, tous les éléments sélectionnés sont désélectionnés lors de la navigation en dehors de l'écran). Mes commandes de navigation sont situés dans un autre modèle de vue qui gère le point de vue des modèles pour chaque écran, donc je ne peux pas mettre n'importe quel de mise en œuvre liées à la vue du modèle, avec la ListBox
là.
J'ai trouvé plusieurs autres moins élégant solutions, mais aucune de ces semblent appliquer une liaison bidirectionnelle entre le point de vue du modèle et de la vue.
Toute aide serait grandement appréciée. Je peux donner un peu de mon code source si cela peut aider à comprendre mon problème.
- ah, je vois, vous avez déjà essayer d'utiliser un comportement. utiliser un BindableCollection pour les éléments sélectionnés, il devrait fonctionner. Si vous avez plus de problèmes, faites le moi savoir. Décrire et nous aurons un coup d'oeil.
- merci de montrer un peu de code, en particulier la SelectedItems et le code XAML. Est SelectedItems d'une propriété? Soupçonner que le comportement lors de la SelectedItems était juste un membre du public de BindableCollection, pas une Propriété.
- Ah, je ne savais pas que la propriété devait être explicitement appelé
SelectedItems
(le mien a été appeléSelectedLanguages
). Maintenant, je reçois unInvalidOperationException
jeté dans laBindableCollection
constructeur lorsque je clique sur le bouton "Retour" à la ligne le répartiteur est appelé avec laRaisePropertyChangedEventHandler
. J'ai essayé il suffit de le mettre dans un bloc try/catch avecDispatcher.BeginInvoke
dans le bloc catch, mais alors les éléments de la liste ne sont pas re-sélectionné lorsque la page est accédée à rentrer.
Vous devez vous connecter pour publier un commentaire.
Essayez de créer un
IsSelected
de propriété sur chacun de vos éléments de données et de liaisonListBoxItem.IsSelected
à la propriétéListBox
contientCultureInfo
éléments, alors serait-il possible d'utiliser votre solution sans créer une classe qui hérite deCultureInfo
et a laIsSelected
propriété? Ou suis-je interpréter votre solution de façon incorrecte?IsSelected
propriété de l'objet pour que cela fonctionneIsSelected
pour les objets de modèle? J'ai fait cela, et a obtenu dans un peu d'un méli-mélo en particulier lorsque la même instance d'un objet de modèle apparaît dans plus d'un endroit (dans un Arbre). Lorsque on est sélectionné, puis ils semblent tous sélectionnés. Ce n'est pas toujours souhaité. Aussi, il me semble que le modèle est "pollué" par la Vue des choses. Quelle est votre expérience?IsSelected
valeur est stockée sur leDataContext
Rachel solutions fonctionne très bien! Mais il y a un problème que j'ai rencontré - si vous remplacez le style de
ListBoxItem
, vous perdez le style original appliquée (dans mon cas responsable pour la mise en évidence de l'élément sélectionné, etc.). Vous pouvez éviter cela en héritant du style d'origine:Remarque le réglage de
BasedOn
(voir cette réponse).
Je ne pouvais pas obtenir de Rachel solution fonctionne, comment je le voulais, mais j'ai trouvé Sandesh de l' réponse de créer un personnalisé propriété de dépendance fonctionne parfaitement pour moi. J'ai juste eu à écrire du code similaire pour une ListBox:
Dans mon Modèle de Vue je viens de référence de la propriété pour obtenir ma liste sélectionnée.
J'ai continué à regarder dans une solution simple pour cela, mais avec pas de chance.
La solution Rachel a est bonne si vous avez déjà Sélectionnés de la propriété sur l'objet à l'intérieur de votre ItemsSource. Si vous ne le faites pas, vous devez créer un Modèle pour que le modèle d'entreprise.
J'ai pris une route différente. Un rapide, mais pas parfait.
Sur votre zone de liste créer un événement pour SelectionChanged.
Mettre en œuvre l'événement sur le code dans votre page XAML.
Tada. Fait.
Cela a été fait avec l'aide de la conversion de SelectedItemCollection à une Liste.
Pas satisfait avec les réponses que j'essayais d'en trouver un par moi-même...
Eh bien il s'avère à être plus comme un hack alors une solution, mais pour moi, ce qui fonctionne parfaitement. Cette Solution utilise MultiBindings d'une manière spéciale.
D'abord, il peut ressembler à une tonne de Code, mais vous pouvez la réutiliser avec très peu d'effort.
J'ai d'abord mis en œuvre une "IMultiValueConverter'
Et un SelectedItems Conteneurs/Emballage:
Maintenant nous allons créer la Liaison de notre zone de liste.SelectedItem (Au Singulier). Remarque: Vous devez créer une Ressource statique pour le "Converter". Cela peut être fait une fois par l'application et être réutilisées pour toutes les listes qui ont besoin du convertisseur.
Dans le ViewModel j'ai créé le Récipient où je peux lier. Il est important d'initialiser avec new() afin de le remplir avec les valeurs.
Et c'est tout. Peut-être que quelqu'un voit quelques améliorations?
Qu'en pensez-Vous?
Voici encore une autre solution. Il est similaire à Ben réponse, mais la liaison fonctionne de deux façons. L'astuce est de mettre à jour le
ListBox
's éléments sélectionnés lorsque les données liées variation des éléments.Malheureusement, je n'ai pas pu utiliser
IList
comme le BindableSelectedItems type. Ce faisant envoyénull
de mon point de vue du modèle, de la propriété, dont le type estIEnumerable<string>
.Voici le code XAML:
Il y a une chose à regarder dehors pour. Dans mon cas, un
ListBox
peut être retiré de la vue. Pour une raison quelconque, ce qui provoque leSelectedItems
la propriété de changer pour une liste vide. Ceci, à son tour, provoque la vue du modèle, de la propriété d'être modifié pour une liste vide. Selon votre cas d'utilisation, cela peut ne pas être souhaitable.C'était une question importante pour moi, certaines des réponses que j'ai vu étaient trop hackish, ou à la réinitialisation de l'
SelectedItems
valeur de la propriété de la rupture de tout code associé à des propriétés OnCollectionChanged événement. Mais j'ai réussi à obtenir une solution réalisable par la modification de la collecte directement et en bonus, il prend même en chargeSelectedValuePath
pour les collections d'objets.Liaison fonctionne exactement comme vous l'aurait attendu MS à l'avoir fait eux-mêmes:
Il n'a pas été testé, mais a passé le premier coup d'œil les inspections. J'ai essayé de rester réutilisables, en utilisant les types de dynamiques sur les collections.
C'était assez facile à faire avec une Commande et les Interactivités EventTrigger. ItemsCount est juste une propriété liée à une utilisation sur votre XAML, si vous souhaitez afficher le compte mis à jour.
XAML:
ViewModel:
S'avère la liaison d'une case à cocher à la propriété IsSelected et de mettre le textblock et case sein d'une pile de panneau fait le tour!