vb@rchiv
VB Classic
VB.NET
ADO.NET
VBA
C#
sevAniGif - als kostenlose Vollversion auf unserer vb@rchiv CD Vol.5  
 vb@rchiv Quick-Search: Suche startenErweiterte Suche starten   RSS-Feeds  | Newsletter  | Impressum  | Datenschutz  | vb@rchiv CD Vol.6  | Shop Copyright ©2000-2017
 
zurück
Rubrik: .NET   |   VB-Versionen: VB200801.02.10
ListView filtern, sortieren und gruppieren in WPF

Dieser Workshop zeigt, wie man ein ListView in WPF (Visual Basic Studio 2008) relativ einfach filtern, sortieren und gruppieren kann und dies auch angemessen darstellt.

Autor:  MaasBewertung:     [ Jetzt bewerten ]Views:  30.667 

Summer-Special bei Tools & Components!
Gute Laune Sommer bei Tools & Components
Top Summer-Special - Sparen Sie teilweise bis zu 120,- EUR
Alle sev-Entwicklerkomponenten und Komplettpakete jetzt bis zu 25% reduziert!
zum Beispiel:
  • Developer CD nur 479,20 EUR statt 599,- EUR
  • sevDTA 3.0 nur 224,30 EUR statt 299,- EUR
  •  
  • vb@rchiv   Vol.6 nur 20,00 EUR statt 24,95 EUR
  • sevCoolbar 3.0 nur 55,20 EUR statt 69,- EUR
  • - Werbung -Und viele weitere Angebote           Aktionspreise nur für kurze Zeit gültig

    Im Folgenenden soll gezeigt werden, wie es mit relativ einfachen Mitteln (das sieht jetzt viel aus, ist aber eigentlich ganz übersichtlich) möglich ist, eine an ein ListView gebundene Collection zu filtern, sortieren und/oder zu gruppieren.

    Zuerst muss eine neue WPF-Applikation erstellt werden:

    Als Basis für die folgenden Beispiele wird nachfolgende Kontakt-Klasse und Enum benutzt, welche Informationen über eine Person beinhaltet. Eine Liste dieser Kontaktdaten wird dann geordnet.

    Imports System.Collections.ObjectModel
    Imports System.ComponentModel
     
    Public Enum KontaktTyp
      Privat
      Geschäftlich
      Sonstige
    End Enum
     
    Public Class Kontakt
     
      Private mTyp As KontaktTyp = KontaktTyp.Sonstige
      Private mName As String = String.Empty
      Private mVorname As String = String.Empty
      Private mGeburtsDatum As Date
     
      Public Property Typ() As KontaktTyp
        Get
          Return mTyp
        End Get
        Set(ByVal value As KontaktTyp)
          mTyp = value
        End Set
      End Property
     
      Public Property Name() As String
        Get
          Return mName
        End Get
        Set(ByVal value As String)
          mName = value
        End Set
      End Property
     
      Public Property Vorname() As String
        Get
          Return mVorname
        End Get
        Set(ByVal value As String)
          mVorname = value
        End Set
      End Property
     
      Public Property Geburtsdatum() As Date
        Get
          Return mGeburtsDatum
        End Get
        Set(ByVal value As Date)
          mGeburtsDatum = value
        End Set
      End Property
     
      Public Sub New()
      End Sub
     
      Public Sub New(ByVal vorname As String, ByVal name As String, _
        ByVal geburtsdatum As Date, ByVal typ As KontaktTyp)
     
        mVorname = vorname
        mName = name
        mGeburtsDatum = geburtsdatum
        mTyp = typ
      End Sub
     
      Public Overrides Function ToString() As String
        Return String.Format("{0}, {1}", mName, mVorname)
      End Function
     
    End Class

    Das Fenster für die Darstellung sieht dann so aus.
    Das Beziehen von Daten oder das Setzen von Eigenschaften läuft fast komplett über DataBinding. Es wird hier vorausgesetzt, dass die Grundlagen des WPF-DataBindings bekannt sind.

    <Window x:Class="Window1"
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation";
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml";
      Title="ListView filtern, sortieren und gruppieren in WPF"
      Height="431"
      Width="681">
      <Grid>
        <Grid.RowDefinitions>
          <RowDefinition Height="1*" />
          <RowDefinition Height="130" />
          <RowDefinition Height="35" />
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
          <ColumnDefinition Width="200" />
          <ColumnDefinition Width="200" />
          <ColumnDefinition Width="200" />
          <ColumnDefinition Width="1*" />
        </Grid.ColumnDefinitions>
        <ListView ItemsSource="{Binding Kontakte}"
          Margin="12"
          Name="ListView1"
          Grid.ColumnSpan="4">
        <ListView.View>
          <GridView>
            <GridViewColumn Width="180"
              Header="Name"
              DisplayMemberBinding="{Binding Name}"/>
            <GridViewColumn Width="140"
              Header="Vorname"
              DisplayMemberBinding="{Binding Vorname}" />
            <GridViewColumn Width="140"
              Header="Typ"
              DisplayMemberBinding="{Binding Typ}" />
            <GridViewColumn Width="140"
              Header="Geburtsdatum"
              DisplayMemberBinding="{Binding Geburtsdatum, StringFormat='{}{0:dd.MM.yyyy}'}" />
            </GridView>
          </ListView.View>
        </ListView>
      </Grid>
    </Window>

    Der code-behind:

    Imports System.Collections.ObjectModel
    Imports System.ComponentModel
     
    Class Window1
     
      Private mKontakte As New ObservableCollection(Of Kontakt)
     
      Public Property Kontakte() As ObservableCollection(Of Kontakt)
        Get
          Return mKontakte
        End Get
        Set(ByVal value As ObservableCollection(Of Kontakt))
          mKontakte = value
        End Set
      End Property
     
      Public Sub New()
        InitializeComponent()
     
        ListView1.DataContext = Me
     
        ' Beispiel Liste
        mKontakte.Add(New Kontakt("Bernd", "Schuster", #1/8/1960#, KontaktTyp.Geschäftlich))
        mKontakte.Add(New Kontakt("Lisa", "Müller", #1/1/1965#, KontaktTyp.Privat))
        mKontakte.Add(New Kontakt("Stefan", "Meyer", #1/2/1970#, KontaktTyp.Sonstige))
        mKontakte.Add(New Kontakt("Klaus", "Schulz", #1/3/1975#, KontaktTyp.Geschäftlich))
        mKontakte.Add(New Kontakt("Martin", "Schmidt", #1/4/1980#, KontaktTyp.Sonstige))
        mKontakte.Add(New Kontakt("Christina", "Fischer", #1/5/1985#, KontaktTyp.Geschäftlich))
        mKontakte.Add(New Kontakt("Kurt", "Wagner", #1/6/1990#, KontaktTyp.Privat))
        mKontakte.Add(New Kontakt("Anne", "Bauer", #1/7/1995#, KontaktTyp.Sonstige))
        mKontakte.Add(New Kontakt("Kai", "Krüger", #1/8/2000#, KontaktTyp.Privat))
      End Sub
     
    End Class

    Das Ganze sollte jetzt so aussehen:

    ListCollectionView

    Das Prinzip in WPF ist es für das ListView sozusagen eine extra Ansicht zu erstellen, die nur im Standardfall der echten Auflistung entspricht. Man kann diese Ansicht beeinflussen, ohne damit die echte Auflistung zu ändern.

    An die ListCollectionView der Kontakte-Liste, mit der man das umsetzen kann, kommt man mit folgendem Code:

    Dim view As ListCollectionView = _
      CType(CollectionViewSource.GetDefaultView(mKontakte), _
      ListCollectionView)

    Um die Ansicht manuell zu aktualisieren, kann man .Refresh() aufrufen. Dies wird nicht benötigt, wenn die Auflistung irgendwie geändert wird. Der Refresh-Vorgang wird dann automatisch ausgelöst. Wenn der Typ der Auflistung INotifyPropertyChanged implementiert, führt das Auslösen des PropertyChanged-Events auch zu einem Refresh.

    view.Refresh()

    Das ist die Aufgabe für den Update-Button, der jetzt hinzugefügt wird.

      <Grid>
        '...
        <Button Grid.Column="2"
          Grid.Row="2"
          HorizontalAlignment="Right"
          Margin="0,6,11,0"
          Name="btnUpdate"
          Width="75"
          Height="23"
          VerticalAlignment="Top">Update
        </Button>
      </Grid>
      Private Sub btnUpdate_Click(ByVal sender As Object, _
        ByVal e As RoutedEventArgs) Handles btnUpdate.Click
     
        Dim view As ListCollectionView = _
          CType(CollectionViewSource.GetDefaultView(mKontakte), _
          ListCollectionView)
        view.Refresh()
      End Sub

    Ich benutze in diesem Beispiel eine ObservableCollection, da diese Vorteile im Gegensatz zur BindingList hat, bzw. deren CollectionView. Die BindingListCollectionView hat genauso wie die ItemCollection des ListView keine CustomSort Eigenschaft. Ansonsten sind BindingList und ObservableCollection im Verhalten gleich was das DataBinding angeht.

    Filtern

    Die Filter-Eigenschaft der ListCollectionView ist vom Typ System.Predicate(Of Object) und diese kann mit einer Funktion bedient werden.
    Diese Funktion sieht dann etwa so aus.

    Public Function Filter(ByVal itemObj As Object) As Boolean
      ' ...
    End Function

    itemObj ist in diesem Fall der Kontakt, welcher überprüft wird. Es wird im Fall einer Aktualisierung der Ansicht für jeden Item diese Funktionaufgerufen. Der Boolean Wert, der zurück gegeben wird, zeigt ganz einfach ob der Item angezeigt wird oder nicht.

    Man könnte diese Funktion nun direkt in die Window-Klasse schreiben, aber da die Filterung von einigen Optionen abhängig gemacht werden und am Ende kein Spagetti-Code rauskommen soll, wird das alles in eine Klasse gepackt.

    Beim Filtern soll es möglich sein nach einem Keyword zu suchen, nur einen bestimmten oder alle KontaktTypen anzuzeigen und eine Grenze für das Geburtsdatum zu setzen. Dazu einfach folgende Filter-Klasse hinzufügen.

    Public Class KontaktFilter
      Private mSuchwort As String = String.Empty
      Private mNurJuengerAls As Date
      Private mFilterTypen As Boolean = False
      Private mErlaubterTyp As KontaktTyp = KontaktTyp.Sonstige
     
      Public Property Suchwort() As String
        Get
          Return mSuchwort
        End Get
        Set(ByVal value As String)
          mSuchwort = value
        End Set
      End Property
     
      Public Property NurJuengerAls() As Date
        Get
          Return mNurJuengerAls
        End Get
        Set(ByVal value As Date)
          mNurJuengerAls = value
        End Set
      End Property
     
      Public Property FilterTypen() As Boolean
        Get
          Return mFilterTypen
        End Get
        Set(ByVal value As Boolean)
          mFilterTypen = value
        End Set
      End Property
     
      Public Property ErlaubterTyp() As KontaktTyp
        Get
          Return mErlaubterTyp
        End Get
        Set(ByVal value As KontaktTyp)
          mErlaubterTyp = value
        End Set
      End Property
     
      Public Function Filter(ByVal itemObj As Object) As Boolean
        Dim item As Kontakt = TryCast(itemObj, Kontakt)
        If item IsNot Nothing Then
          ' Wenn eine Bedingung nicht erfüllt wird, ist der Item raus
          If mSuchwort <> String.Empty Then
            ' Nach Keyword suchen
            If Not (item.Vorname.ToLower.Contains(mSuchwort.ToLower) Or _
              item.Name.ToLower.Contains(mSuchwort.ToLower)) Then
              Return False
            End If
          End If
     
          If mFilterTypen Then
            ' Nur bestimmten Typ erlauben
            If mErlaubterTyp <> item.Typ Then
              Return False
            End If
          End If
     
          ' Geburtstagsgrenze
          If item.Geburtsdatum < mNurJuengerAls Then
            Return False
          End If
     
          ' und so weiter ...
     
          Return True
        Else
          Return False
        End If
      End Function
    End Class

    Die Window-Klasse wird mit folgendem Code erweitert.

    Class Window1
     
      Private mFilter As New KontaktFilter
     
      ' Brauchen wir für das DataBinding
      Public ReadOnly Property Filter() As KontaktFilter
        Get
          Return mFilter
        End Get
      End Property
     
      ...
     
      Public Sub New()
        txtNurJuengerAls.DataContext = Me
        txtSuchwort.DataContext = Me
        cmbTyp.ItemsSource = New KontaktTyp() {KontaktTyp.Geschäftlich, _
                                               KontaktTyp.Privat, _
                                               KontaktTyp.Sonstige}
        cmbTyp.DataContext = Me
        chkFilterTypen.DataContext = Me
     
        ...
     
        Dim view As ListCollectionView = _
          CType(CollectionViewSource.GetDefaultView(mKontakte), _
          ListCollectionView)
        ' Hier wird der zu benutzende Filter gesetzt;
        ' jede Änderung im Filter wird beim Refresh übernommen, 
        ' da die Funktion neu aufgerufen wird
        view.Filter = New Predicate(Of Object)(AddressOf mFilter.Filter)
      End Sub
     
    End Class

    Window-XAML

    <Window x:Class="Window1" >
      <Grid>
     
        '...
     
        <GroupBox Grid.Row="1" Header="Filter" Name="GroupBox1" Margin="5,0" >
          <Grid>
            <TextBox Height="23"
              Margin="47,13,11,0"
              Name="txtNurJuengerAls"
              VerticalAlignment="Top"
              Text="{Binding Filter.NurJuengerAls,Mode=TwoWay,StringFormat='{}{0:dd.MM.yyyy}'}" />
            <TextBlock Height="21"
              Margin="7,15,0,0"
              Name="TextBlock1"
              VerticalAlignment="Top"
              HorizontalAlignment="Left"
              Width="40"
              Text="Geb." />
            <TextBox Margin="47,42,11,0"
              Name="txtSuchwort"
              Height="23.04"
              VerticalAlignment="Top"
              Text="{Binding Filter.Suchwort,Mode=TwoWay}" />
            <TextBlock HorizontalAlignment="Left"
              Margin="7,44,0,0"
              Name="TextBlock2"
              Text="Name"
              Width="40"
              Height="21.04"
              VerticalAlignment="Top" />
            <ComboBox Height="23"
              Margin="47,71.04,11,0"
              Name="cmbTyp"
              VerticalAlignment="Top"
              SelectedItem="{Binding Filter.ErlaubterTyp,Mode=TwoWay}"
              IsEnabled="{Binding IsChecked,ElementName=chkFilterTypen}"/>
            <CheckBox IsChecked="{Binding Filter.FilterTypen,Mode=TwoWay}"
              IsThreeState="False" Height="16"
              Margin="7,0,0,17"
              Name="chkFilterTypen"
              VerticalAlignment="Bottom"
              HorizontalAlignment="Left"
              Width="41">Typ</CheckBox>
          </Grid>
        </GroupBox>
      </Grid>
    </Window>

    Jetzt einfach mal verschiedene Keywords (Buchstaben oder Teile von Namen) oder die anderen Optionen ausprobieren und danach "Update" klicken.

    Sortieren

    Um sortieren zu können muss man eine Klasse erstellen, welche das Interface IComparer implementiert. Damit werden dann die verschiedenen Items verglichen und geordnet. An sich verläuft alles wie bei einem normalen Comparer.

    In dieser Klasse gibt es noch die Option der Richtung der Sortierung und der Eigenschaft des Kontakts nach dem sortiert wird.

    Imports System.ComponentModel
     
    Public Enum KontaktEigenschaft
      Name
      Vorname
      Typ
      Geburtsdatum
    End Enum
     
    Public Class KontaktSortierer
      Implements IComparer
     
      Private mSortiertNach As KontaktEigenschaft = KontaktEigenschaft.Name
      Private mSortierRichtung As ListSortDirection = ListSortDirection.Ascending
     
      Public Property SortiertNach() As KontaktEigenschaft
        Get
          Return mSortiertNach
        End Get
        Set(ByVal value As KontaktEigenschaft)
          mSortiertNach = value
        End Set
      End Property
      Public Property SortierRichtung() As ListSortDirection
        Get
          Return mSortierRichtung
        End Get
        Set(ByVal value As ListSortDirection)
          mSortierRichtung = value
        End Set
      End Property
     
      Public Function Compare(ByVal x As Object, ByVal y As Object) As Integer _
        Implements System.Collections.IComparer.Compare
     
        Dim itemX As Kontakt = TryCast(x, Kontakt)
        Dim itemY As Kontakt = TryCast(y, Kontakt)
        If itemX IsNot Nothing AndAlso itemY IsNot Nothing Then
          Dim sortMultiplier As Integer = 0
          If mSortierRichtung = ListSortDirection.Ascending Then : sortMultiplier = 1
          Else : sortMultiplier = -1
          End If
          Select Case mSortiertNach
            Case KontaktEigenschaft.Name
              Return String.Compare(itemX.Name, itemY.Name) * sortMultiplier
            Case KontaktEigenschaft.Vorname
              Return String.Compare(itemX.Vorname, itemY.Vorname) * sortMultiplier
            Case KontaktEigenschaft.Typ
              If CInt(itemX.Typ) > CInt(itemY.Typ) Then
                Return 1 * sortMultiplier
              ElseIf CInt(itemX.Typ) < CInt(itemY.Typ) Then
                Return -1 * sortMultiplier
              Else
                Return 0
              End If
            Case KontaktEigenschaft.Geburtsdatum
              Return Date.Compare(itemX.Geburtsdatum, itemY.Geburtsdatum) * sortMultiplier
          End Select
        End If
        Return -1
      End Function
     
    End Class

    Zur Window-Klasse kommt folgendes hinzu:

    Class Window1
     
      Private mSortierung As New KontaktSortierer
     
      ' Brauchen wir für das DataBinding
      Public ReadOnly Property Sortierung() As KontaktSortierer
        Get
          Return mSortierung
        End Get
      End Property
     
      ' ...
     
      Public Sub New()
        cmbSortiertNach.ItemsSource = _
          New KontaktEigenschaft() {KontaktEigenschaft.Name, _
          KontaktEigenschaft.Vorname, _
          KontaktEigenschaft.Typ, _
          KontaktEigenschaft.Geburtsdatum}
     
        cmbSortiertNach.DataContext = Me
        cmbSortierRichtung.ItemsSource = _
          New ListSortDirection() {ListSortDirection.Ascending, _
          ListSortDirection.Descending}
        cmbSortierRichtung.DataContext = Me
     
        ' ...
     
        Dim view As ListCollectionView = _
          CType(CollectionViewSource.GetDefaultView(mKontakte), _
          ListCollectionView)
        view.Filter = New Predicate(Of Object)(AddressOf mFilter.Filter)
     
        ' Die Sortierung hinzufügen
        view.CustomSort = mSortierung
      End Sub
     
    End Class

    Window-XAML

    <Window x:Class="Window1" >
      <Grid>
        '...
     
        <GroupBox Header="Sortierung" Name="GroupBox2" Grid.Column="1" Grid.Row="1" Margin="5,0">
          <Grid>
            <ComboBox SelectedItem="{Binding Sortierung.SortiertNach,Mode=TwoWay}"
              Height="23" Margin="15,13,15,0"
              Name="cmbSortiertNach"
              VerticalAlignment="Top" />
            <ComboBox SelectedItem="{Binding Sortierung.SortierRichtung,Mode=TwoWay}"
              Margin="15,42,15,0"
              Name="cmbSortierRichtung"
              Height="23.04"
              VerticalAlignment="Top" />
          </Grid>
        </GroupBox>
      </Grid>
    </Window>

    Gruppieren

    Das Gruppieren ist erstmal das Leichteste von allem. Es reicht eigentlich folgendes der Ansicht hinzuzufügen.

    view.GroupDescriptions.Add(New PropertyGroupDescription("Typ"))

    Damit würden die Items nach der Eigenschaft Typ gruppiert werden.

    Man kann es aber auch noch individueller gestalten, z.B. bei Eigenschaften, wo die Auswahlmöglichkeit nicht so begrenzt ist. Würde man nach der Eigenschaft Geburtsdatum gruppieren, würde in diesem Beispiel jeder Kontakt seine eigene Gruppe bekommen. Das ist aber nicht der tiefere Sinn der Gruppierung, also kann man noch einen IValueConverter übergeben. Mit diesem können die Items individuell gruppiert werden. Wenn kein Eigenschaftenname übergeben wird, wird dem Converter das gesamte Item-Objekt übergeben. Bei einem übergebenen Namen wird das Objekt der Eigenschaft übergeben, in dem folgendem Fall ein Datum. Die Gruppierer-Klasse kann natürlich genauso individuell gestaltet werden wie der Filter und der Sortierer.

    In diesem Beispiel werden die Geburtstage in Dekaden gruppiert.

    Public Class GeburtsdekadenGruppierer
      Implements IValueConverter
     
      Public Function Convert(ByVal value As Object, _
        ByVal targetType As System.Type, _
        ByVal parameter As Object, _
        ByVal culture As System.Globalization.CultureInfo) As Object _
        Implements System.Windows.Data.IValueConverter.Convert
     
        If value.GetType Is GetType(Date) Then
          Dim d As Date = CDate(value)
          If d > #1/1/1950# And d < #1/1/1959# Then
            Return "1950 - 1959"
          ElseIf d > #1/1/1960# And d < #1/1/1969# Then
            Return "1960 - 1969"
          ElseIf d > #1/1/1970# And d < #1/1/1979# Then
            Return "1970 - 1979"
          ElseIf d > #1/1/1980# And d < #1/1/1989# Then
            Return "1980 - 1989"
          ElseIf d > #1/1/1990# And d < #1/1/1999# Then
            Return "1990 - 1999"
          ElseIf d > #1/1/2000# And d < #1/1/2009# Then
            Return "2000 - 2009"
          Else
            Return "2010 - Heute"
          End If
        Else
          Return "Sonstige"
        End If
      End Function
     
      Public Function ConvertBack(ByVal value As Object, _
        ByVal targetType As System.Type, _
        ByVal parameter As Object, _
        ByVal culture As System.Globalization.CultureInfo) As Object _
        Implements System.Windows.Data.IValueConverter.ConvertBack
     
        Throw New NotSupportedException("Rückwärtige Konvertierung wird nicht unterstützt.")
      End Function
    End Class

    Um das Ganze anzuwenden, wird der Window-Klasse folgendes hinzugefügt:

    Class Window1
     
      Private mGruppierungAktiviert As Boolean = False
      Private mGruppierung As KontaktEigenschaft = KontaktEigenschaft.Typ
     
      ' Brauchen wir für das DataBinding
      Public Property GruppierungAktiviert() As Boolean
        Get
          Return mGruppierungAktiviert
        End Get
        Set(ByVal value As Boolean)
          mGruppierungAktiviert = value
        End Set
      End Property
     
      Public Property Gruppierung() As KontaktEigenschaft
        Get
          Return mGruppierung
        End Get
        Set(ByVal value As KontaktEigenschaft)
          mGruppierung = value
        End Set
      End Property
     
      ' ...
     
      Public Sub New()
        chkGrpAktiviert.DataContext = Me
        cmbGruppierung.ItemsSource = _
          New KontaktEigenschaft() {KontaktEigenschaft.Typ, _
          KontaktEigenschaft.Geburtsdatum}
        cmbGruppierung.DataContext = Me
     
        ' ...
     
      End Sub
     
     
      Private Sub btnUpdate_Click(ByVal sender As Object, _
        ByVal e As RoutedEventArgs) Handles btnUpdate.Click
     
        Dim view As ListCollectionView = _
          CType(CollectionViewSource.GetDefaultView(mKontakte), _
          ListCollectionView)
        view.GroupDescriptions.Clear()
     
        If mGruppierungAktiviert Then
          If mGruppierung = KontaktEigenschaft.Typ Then
            view.GroupDescriptions.Add(New PropertyGroupDescription("Typ"))
          ElseIf mGruppierung = KontaktEigenschaft.Geburtsdatum Then
            view.GroupDescriptions.Add(New _
            PropertyGroupDescription("Geburtsdatum", New GeburtsdekadenGruppierer))
          End If
        End If
     
        view.Refresh()
      End Sub
     
    End Class

    Window-XAML

    <Window x:Class="Window1" >
      <Grid>
        '...
     
        <GroupBox Header="Gruppierung" Margin="5,0" Name="GroupBox3"
          Grid.Column="2" Grid.Row="1">
          <Grid>
            <CheckBox IsChecked="{Binding GruppierungAktiviert,Mode=TwoWay}"
              Margin="17,15,23,0"
              Name="chkGrpAktiviert"
              Height="16.04"
              VerticalAlignment="Top">Aktiviert</CheckBox>
            <ComboBox SelectedItem="{Binding Gruppierung,Mode=TwoWay}"
              Margin="17,44,23,0"
              Name="cmbGruppierung"
              Height="23.04"
              VerticalAlignment="Top" />
          </Grid>
        </GroupBox>
      </Grid>
    </Window>

    Jetzt werden die Items zwar schon gruppiert, aber das ist noch nicht so richtig erkennbar. Dafür bietet WPF auch eine Lösung mit der Bestimmung eines eigenen Styles für ein GroupItem. In diesem Style werden die Items dann in Expandern gruppiert.

    Dafür dem ListView den folgenden GroupStyle hinzufügen.

    <Window x:Class="Window1" >
      <Grid>
        '...
     
        <ListView ItemsSource="{Binding Kontakte}"
          Margin="12"
          Name="ListView1"
          Grid.ColumnSpan="4">
          <ListView.View>
            '...
          </ListView.View>
     
          <ListView.GroupStyle>
            <GroupStyle>
              <GroupStyle.ContainerStyle>
                <Style TargetType="{x:Type GroupItem}">
                  <Setter Property="Margin" Value="0,0,0,5"/>
                  <Setter Property="Template">
                    <Setter.Value>
                      <ControlTemplate TargetType="{x:Type GroupItem}">
                        <Expander Margin="2,0,2,0" Header="{Binding Path=Content.Name,
                          RelativeSource={RelativeSource
                          Mode=FindAncestor,
                          AncestorType={x:Type GroupItem}}}"
                          BorderBrush="Black"
                          BorderThickness="1"
                          Background="LightBlue">
                          <Expander.Content>
                            <Border Background="White"
                              Margin="2"
                              CornerRadius="3">
                              <ItemsPresenter />
                            </Border>
                          </Expander.Content>
                        </Expander>
                      </ControlTemplate>
                    </Setter.Value>
                  </Setter>
                </Style>
              </GroupStyle.ContainerStyle>
            </GroupStyle>
          </ListView.GroupStyle>
        </ListView>
     
        '...
      </Grid>
    </Window>

    Das Ganze sollte am Ende so aussehen:

    So... das war's dann auch schon.
    Viel Spaß damit.

     Download FilterSortGroup (22 KB)

    Dieser Workshop wurde bereits 30.667 mal aufgerufen.

    Über diesen Workshop im Forum diskutieren
    Haben Sie Fragen oder Anregungen zu diesem Workshop, können Sie gerne mit anderen darüber in unserem Forum diskutieren.

    Neue Diskussion eröffnen

    nach obenzurück


    Anzeige

    Kauftipp Unser Dauerbrenner!Diesen und auch alle anderen Workshops finden Sie auch auf unserer aktuellen vb@rchiv  Vol.6
    (einschl. Beispielprojekt!)

    Ein absolutes Muss - Geballtes Wissen aus mehr als 8 Jahren vb@rchiv!
    - nahezu alle Tipps & Tricks und Workshops mit Beispielprojekten
    - Symbol-Galerie mit mehr als 3.200 Icons im modernen Look
    Weitere Infos - 4 Entwickler-Vollversionen (u.a. sevFTP für .NET), Online-Update-Funktion u.v.m.
     
       

    Druckansicht Druckansicht Copyright ©2000-2017 vb@rchiv Dieter Otter
    Alle Rechte vorbehalten.
    Microsoft, Windows und Visual Basic sind entweder eingetragene Marken oder Marken der Microsoft Corporation in den USA und/oder anderen Ländern. Weitere auf dieser Homepage aufgeführten Produkt- und Firmennamen können geschützte Marken ihrer jeweiligen Inhaber sein.

    Diese Seiten wurden optimiert für eine Bildschirmauflösung von mind. 1280x1024 Pixel