2010-08-12 6 views
1

Je lie des données ListView à une collection provenant d'une couche de service. En réponse aux événements, le modèle de vue associé à ListView actualise les données de ListView. Afin de récupérer les données mises à jour, le vm récupère une nouvelle instance de collection à partir de la couche de service. Les éléments de cette collection sont Equals() mais pas ReferenceEquals() pour les éléments équivalents de la collection précédemment retournée.Remplacement d'ItemsSource de ListView sans perte de SelectedItem

Pouvez-vous recommander une approche qui évite les inconvénients des approches ci-dessous tout en permettant au vm de brancher ces données dans le ListView sans que ListView ne perde son SelectedItem?

Merci,
Ben


Une approche simple (voir le code de modèle, le SelectedItem de ListView & ItemsSource sont liés à des propriétés liées à l'identique sur le vm):

var selectedItem = SelectedItem; 
ItemsSource = service.GetData(); 
SelectedItem = Accounts.SingleOrDefault(x => x.Equals(selectedItem)); 

Cette approche semble moche. Il implique également SelectedItem en cours de réinitialisation - un problème potentiel si la modification de SelectedItem modifie la modification de détail à partir d'un formulaire maître-détail. (Le paramétrage de ItemsSource dans SelectedItem est effacé, ce qui explique pourquoi il est réinitialisé sur la dernière ligne.)

Une autre approche consiste à écrire un adaptateur qui charge une ObservableCollection <> avec des objets proxy pointant vers les données renvoyées à partir de la valeur initiale. appel de la couche de service. Chaque fois que des données mises à jour sont extraites de la couche de service, les objets proxy sont mis à jour pour pointer vers les objets nouvellement récupérés. De cette façon, le ItemsSource de ListView n'a pas besoin d'être réinitialisé pour mettre à jour ListView (il reste lié à la même ObservableCollection <>) ce qui signifie que SelectedItem ne sera pas réinitialisé. Un inconvénient de cette approche est la quantité de code impliqué.

+0

J'ai écrit un billet de blog décrivant la première solution que je proposais plus en détail: http://bengribaudo.com/blog/2010/09/14/199/keeping-selected-item-selected-when-changing- listviews-itemssource –

Répondre

0

Je fini par écrire le code mappeur qui a chargé un ObservableCollection avec des objets proxy pointant vers les objets réels récupérés à partir de la couche de service. Chaque fois qu'une mise à jour était extraite de la couche de service, le code de mappeur ajoutait/supprimait/mettait à jour les objets proxy, le cas échéant.

0

hmm ... Que diriez-vous que:

gestionnaires d'événements de registre pour SelectionChanged et DataContextChanged sur le ListView:

<ListView Name="listView" SelectionChanged="listView_SelectionChanged" DataContextChanged="listView_DataContextChanged" /> 

Dans le gestionnaire SelectionChanged enregistrer le SelectedItem dans la balise de ListView

private void listView_SelectionChanged(object sender, SelectionChangedEventArgs e) 
{ 
    (sender as ListView).Tag = (sender as ListView).SelectedItem; 
} 

Une fois que le DataContext pour le ListView a changé, d'évaluer la dernière SelectedItem qui a été enregistré dans l'étiquette contre la nouvelle collection et définir la nouvelle i tem de cette collection:

private void listView_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e) 
    { 
     List<CustomClass> newList = e.NewValue as List<CustomClass>; 
     if (newList != null && (sender as ListView).Tag != null) 
     { 
      foreach (CustomClass cClass in newList) 
       if (cClass.Equals((sender as ListView).Tag as CustomClass)) 
        (sender as ListView).SelectedItem = cClass; 
     } 
    } 
+0

Merci pour cette réponse. J'essaie d'éviter d'utiliser les callbacks comme C# WPF nécessite un code-behind de les utiliser au lieu de les laisser être réglés via de la limite des données sur le modèle de vue. –