Yogu - So 06.03.11 18:03
Titel: WPF-ListView mit dynamischen Gruppen
Hallo,
ich arbeite mich gerade in das WPF-Framework ein und habe nun eine ListView-Komponente, die an eine
ObservableCollection gebunden ist. Die Einträge selbst implementieren
INotifyPropertyChanged. Die Einträge in der ListView werden nach dem Wert einer Eigenschaft gruppiert. Mein Problem ist nun, dass sich ein Eintrag nicht umgruppiert, wenn sich der wert der Eigenschaft ändert.
Im Anhang findet ihr ein WPF-Projekt, in dem das Problem demonstriert wird. Dort werden ein paar Objekte mit unterschiedlichen Werten für die Gruppierungs-Eigenschaft
Category erstellt und in die Liste, die als Datenquelle dient, hinzugefügt. Per Knopfdruck wird die
Category-Eigenschaft eines Objektes verändert. Der Wert dieser Eigenschaft auch mithilfe einer normalen Bindung für jeden Eintrag in der Liste angezeigt - und dieser Wert wird aktualisiert.
Das wichtigste ist wohl das XAML-Dokument:
XML-Daten
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34:
| <Window x:Class="WpfApplication1.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="MainWindow" Height="350" Width="525"> <Window.Resources> <CollectionViewSource x:Key="Source" Source="{Binding}"> <CollectionViewSource.GroupDescriptions> <PropertyGroupDescription PropertyName="Category"/> </CollectionViewSource.GroupDescriptions> </CollectionViewSource> </Window.Resources> <Grid> <Grid.RowDefinitions> <RowDefinition Height="*" /> <RowDefinition Height="Auto" /> </Grid.RowDefinitions> <ListView ItemsSource="{Binding Source={StaticResource Source}}" Grid.Row="0"> <ListView.GroupStyle> <x:Static Member="GroupStyle.Default"/> </ListView.GroupStyle> <ListView.ItemTemplate> <DataTemplate> <StackPanel Orientation="Horizontal"> <TextBlock Text="{Binding Text}" /> <TextBlock Text=" (" /> <TextBlock Text="{Binding Category}" /> <TextBlock Text=")" /> </StackPanel> </DataTemplate> </ListView.ItemTemplate> </ListView> <Button Grid.Row="1" Click="Button_Click">Change</Button> </Grid> </Window> |
Ich hoffe, ihr könnt mir weiterhelfen. Ich habe noch niemanden gefunden, der mein Problem teilt.
Danke im Voraus!
Grüße,
Yogu
Yogu - So 06.03.11 18:47
Hallo,
das ist genau das, was ich gesucht habe, nur hab ich bei der falschen Klasse gesucht -
ListView statt
CollectionViewSource. Und die Lösung funktioniert einwandfrei, also vielen Dank! :D
das Thema, auf das in dem verlinkten Beitrag verwiesen wird, existiert zwar nicht mehr, aber im
Google-Cache [
http://webcache.googleusercontent.com/search?q=cache%3Ahttp%3A%2F%2Fforums.microsoft.com%2FMSDN%2FShowPost.aspx%3FPostID%3D2847501%26SiteID%3D1&ie=utf-8&oe=utf-8&aq=t&rls=org.mozilla:de:official&client=firefox-a] ist es noch drin. Da ich aber nicht weiß, wie lange der Cache noch funktioniert und der Quelltext außerdem mit nicht gerade ansprechend aufbereitet ist (es scheint ein Stylessheet zu fehlen), hier nochmal die ganze Klasse:
C#-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71: 72: 73: 74: 75: 76: 77: 78: 79: 80: 81: 82: 83: 84: 85: 86: 87: 88: 89: 90: 91: 92: 93: 94: 95:
| using System; using System.Collections; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Collections.Specialized; using System.Linq; using System.Text; using System.ComponentModel; using System.Windows.Data; using System.Diagnostics;
namespace WpfApplication1 { public class AutoRefreshCollectionViewSource : CollectionViewSource { protected override void OnSourceChanged(object oldSource, object newSource) { if (oldSource != null) { SubscribeSourceEvents(oldSource, true); }
if (newSource != null) { SubscribeSourceEvents(newSource, false); }
base.OnSourceChanged(oldSource, newSource); }
private void Item_PropertyChanged(object sender, PropertyChangedEventArgs e) { bool refresh = false;
foreach (SortDescription sort in SortDescriptions) { if (sort.PropertyName == e.PropertyName) { refresh = true; break; } }
if (!refresh) { foreach (GroupDescription group in GroupDescriptions) { PropertyGroupDescription propertyGroup = group as PropertyGroupDescription;
if (propertyGroup != null && propertyGroup.PropertyName == e.PropertyName) { refresh = true; break; } } }
if (refresh) { View.Refresh(); } }
private void Source_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e) { if (e.Action == NotifyCollectionChangedAction.Add) { SubscribeItemsEvents(e.NewItems, false); } else if (e.Action == NotifyCollectionChangedAction.Remove) { SubscribeItemsEvents(e.OldItems, true); } else { throw new NotImplementedException(); } }
private void SubscribeItemEvents(object item, bool remove) { INotifyPropertyChanged notify = item as INotifyPropertyChanged;
if (notify != null) { if (remove) { notify.PropertyChanged -= Item_PropertyChanged; } else { notify.PropertyChanged += Item_PropertyChanged; } } }
private void SubscribeItemsEvents(IEnumerable items, bool remove) { foreach (object item in items) { SubscribeItemEvents(item, remove); } }
private void SubscribeSourceEvents(object source, bool remove) { INotifyCollectionChanged notify = source as INotifyCollectionChanged;
if (notify != null) { if (remove) { notify.CollectionChanged -= Source_CollectionChanged; } else { notify.CollectionChanged += Source_CollectionChanged; } }
SubscribeItemsEvents((IEnumerable)source, remove); } } } |
Grüße,
Yogu