2010-06-12 4 views
0

J'ai un ListView et ObservableCollection dans mon application wpf. Je veux lier expression LINQ à ListView:bind linq expression

lv_Results.DataContext = store.Where(x => x.PR > 5).ToList(); 
tempStore = new M1Store() 
          { 
           SiteName = siteName, 
           Date = date, 
           url = IndexedPage, 
           TCY = YandexTCY.GetYandexTCY(IndexedPage), 
           PR = Pagerank.GetPR(IndexedPage) 
          }; 
      store.Add(tempStore); 

Mais quand j'ajouter de nouveaux éléments à la collection de magasin, lv_Results doesnt mises à jour. Comment puis-je mettre à jour ListView?

Répondre

1

Votre problème est que vous voulez que la condition "Où" soit évaluée en continu sur tous les éléments ajoutés à la collection "store". L'opérateur LINQ "Where" n'est pas conçu pour cela. Au contraire, quand il est énuméré par le ListView, il scanne votre collection exactement une fois puis l'ignore à partir de là.

Découvrez Continuous LINQ. Il est conçu pour faire exactement ce que vous recherchez et peut être utilisé presque comme un remplacement direct pour les requêtes LINQ standard.

Limites de la LINQ implémentation intégrée

Le LINQ intégré des méthodes d'extension ont une limitation fondamentale en ce que les collections qu'ils produisent ne prennent pas en charge INotifyPropertyChanged. Ainsi, peu importe le degré de modification des données sous-jacentes, le client ne recevra jamais de notification indiquant que la collection a changé et n'actualisera donc jamais son affichage des données. L'utilisateur jrista fait remarquer dans les commentaires que les méthodes LINQ intégrées produisent effectivement des données à jour si elles sont énumérées à nouveau. Bien que vrai, cela n'a aucun effet pratique. Aucun contrôle WinForms ou WPF ne contient de code pour ré-énumérer périodiquement sa source de données. Les raisons de ne pas le faire sont évidemment évidentes: ce serait terriblement inutile. Si vous ré-énumérez 10 fois par seconde et qu'il faut 10ms pour ré-énumérer et analyser les changements, vous utiliserez 10% de votre CPU pour un seul contrôle!

+0

En fait, votre commentaire sur Où est complètement incorrect. Où va chercher de nouveaux éléments ajoutés à la collection de magasin chaque fois que IEnumerable créé par itreated. Ce n'est que lors de l'appel à ToList que les résultats sont "encadrés dans le temps", car ils sont ensuite itérés et ajoutés à une autre collection. S'il vous plaît regardez l'interne où itérateurs via réflecteur: WhereArrayIterator , WhereEnumerableIterator , WhereListIterator . Dans l'état initial, ce qui suit est exécuté: this.enumerator = this.source.GetEnumerator(); Cela récupère un énumérateur de la source au moment de l'itération. – jrista

+0

@jrista: Non, désolé, vous avez tort à ce sujet. Dans le code de Neir0, le "moment de l'itération" que vous mentionnez est exactement le moment où le DataContext est assigné. Le ListView énumère immédiatement son ItemsSource et le fait ** exactement une fois **. Par conséquent, la condition Where scanne la collection ** exactement une fois **. Peu importe que Neir0 utilise ToList(): Il obtiendra exactement les mêmes résultats. (En fait, il l'a fait.) Il ne se mettrait à jour que si ListView ré-énumérait périodiquement la collection, ce qui n'est pas le cas. Donc ma réponse ** est ** correcte. –

+0

@jrista: Je ne voulais pas dire que vous ne comprenez pas comment fonctionne Où. J'essaie juste de faire remarquer que vous étiez tellement concentré sur les internes de Où vous avez manqué la grande image - qu'aucune des fonctionnalités intégrées de LINQ dans NET Framework n'est continue, et en supprimant .ToList() dans le code de Neir0 répare pas ça. Les gens de LINQ continu ont développé leur système pour y remédier. J'ai aussi développé quelque chose de très similaire il y a plusieurs années (donc j'ai aussi une très bonne compréhension de LINQ) mais mon code n'est pas encore du domaine public donc j'ai pointé Neir0 vers Continuous LINQ à la place. –

0

Ajoutez un .ToList() à votre code, LINQ évalue lazy, donc il n'apporte des résultats que lorsque cela est nécessaire, .ToList() est un opérateur gourmand et force une évaluation.

[modifier]

Désolé, missunterstood votre première version de la question :)

Voici ma solution:

ObservableCollection<M1Store> l = store.Where(x => x.PR > 5); 
lv_Results.DataContext = l; 

Cest tout simplement tous, dans toutes les étapes suivantes, changer la collection Observable l:

List<M1Store> otherList = GetFromAnywhere(); 
otherList.ForEach(e => l.Add(e)); 

Ici les internes de l'observabl e Collection mettra à jour le listView dans l'interface utilisateur.

+0

Cela ne marche pas. Je lie la collection de magasins quand elle est vide et ajoute des éléments après la liaison. – Neir0

1

Mettez vos résultats LINQ dans une ObservableCollection. La liaison de données WPF et Silverlight nécessite que les collections génèrent des notifications de modification, et ObservableCollection le fait pour vous. Sinon, vous devrez l'implémenter vous-même, ce qui est plus douloureux et totalement inutile.

0

Les résultats de l'expression LINQ sont introduits dans une nouvelle liste (de T) qui ne déclenche pas les événements PropertyChanged ou CollectionChanged. Le moyen le plus simple de le faire fonctionner est de récupérer les résultats que vous voulez, puis de remplir une ObservableCollection (de T) avec les résultats que vous voulez afficher. Lorsque ObservableCollection est ajouté, les nouveaux éléments apparaissent dans ListView.