Autor Beitrag
Yogu
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2598
Erhaltene Danke: 156

Ubuntu 13.04, Win 7
C# (VS 2013)
BeitragVerfasst: So 06.03.11 18:03 
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:

ausblenden volle Höhe 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
Einloggen, um Attachments anzusehen!
Kha
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 3803
Erhaltene Danke: 176

Arch Linux
Python, C, C++ (vim)
BeitragVerfasst: So 06.03.11 18:27 

_________________
>λ=

Für diesen Beitrag haben gedankt: Yogu
Yogu Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2598
Erhaltene Danke: 156

Ubuntu 13.04, Win 7
C# (VS 2013)
BeitragVerfasst: 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 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:

ausblenden volle Höhe 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 {
        // TODO: Support this
        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