Gewusst wie: Gruppieren, Sortieren und Filtern von Daten im DataGrid-SteuerelementHow to: Group, sort, and filter data in the DataGrid control

Es ist oft hilfreich, Daten in einer DataGrid auf unterschiedliche Weise anzuzeigen, indem Sie die Daten gruppieren, Sortieren und filtern.It is often useful to view data in a DataGrid in different ways by grouping, sorting, and filtering the data. Um die Daten in einem DataGridzu gruppieren, zu sortieren und zu filtern, binden Sie Sie an einen CollectionView, der diese Funktionen unterstützt.To group, sort, and filter the data in a DataGrid, you bind it to a CollectionView that supports these functions. Sie können dann mit den Daten in der CollectionView arbeiten, ohne dass sich dies auf die zugrunde liegenden Quelldaten auswirkt.You can then work with the data in the CollectionView without affecting the underlying source data. Die Änderungen in der Auflistungs Ansicht werden in der DataGrid-Benutzeroberfläche widergespiegelt.The changes in the collection view are reflected in the DataGrid user interface (UI).

Die CollectionView-Klasse stellt Gruppierungs-und Sortierfunktionen für eine Datenquelle bereit, die die IEnumerable-Schnittstelle implementiert.The CollectionView class provides grouping and sorting functionality for a data source that implements the IEnumerable interface. Die CollectionViewSource-Klasse ermöglicht es Ihnen, die Eigenschaften einer CollectionView von XAML festzulegen.The CollectionViewSource class enables you to set the properties of a CollectionView from XAML.

In diesem Beispiel ist eine Auflistung von Task-Objekten an eine CollectionViewSourcegebunden.In this example, a collection of Task objects is bound to a CollectionViewSource. Der CollectionViewSource wird als ItemsSource für die DataGridverwendet.The CollectionViewSource is used as the ItemsSource for the DataGrid. Gruppieren, Sortieren und Filtern werden auf dem CollectionViewSource ausgeführt und in der DataGrid-Benutzeroberfläche angezeigt.Grouping, sorting, and filtering are performed on the CollectionViewSource and are displayed in the DataGrid UI.

Gruppierte Daten in einem DataGrid Gruppierte Daten in einem DataGridGrouped data in a DataGrid Grouped data in a DataGrid

Verwenden von CollectionViewSource als ItemsSourceUsing a CollectionViewSource as an ItemsSource

Zum Gruppieren, Sortieren und Filtern von Daten in einem DataGrid-Steuerelement binden Sie die DataGrid an eine CollectionView, die diese Funktionen unterstützt.To group, sort, and filter data in a DataGrid control, you bind the DataGrid to a CollectionView that supports these functions. In diesem Beispiel ist der DataGrid an eine CollectionViewSource gebunden, die diese Funktionen für einen List<T> von Task Objekten bereitstellt.In this example, the DataGrid is bound to a CollectionViewSource that provides these functions for a List<T> of Task objects.

So binden Sie ein DataGrid an eine CollectionViewSourceTo bind a DataGrid to a CollectionViewSource

  1. Erstellen Sie eine Datensammlung, die die IEnumerable-Schnittstelle implementiert.Create a data collection that implements the IEnumerable interface.

    Wenn Sie List<T> zum Erstellen der Sammlung verwenden, sollten Sie eine neue Klasse erstellen, die von List<T> erbt, anstatt eine Instanz von List<T>zu instanziieren.If you use List<T> to create your collection, you should create a new class that inherits from List<T> instead of instantiating an instance of List<T>. Dies ermöglicht es Ihnen, Daten an die Sammlung in XAML zu binden.This enables you to data bind to the collection in XAML.

    Hinweis

    Die Objekte in der Auflistung müssen die INotifyPropertyChanged geänderte Schnittstelle und die IEditableObject Schnittstelle implementieren, damit die DataGrid ordnungsgemäß auf Eigenschafts Änderungen und Bearbeitungen reagieren können.The objects in the collection must implement the INotifyPropertyChanged changed interface and the IEditableObject interface in order for the DataGrid to respond correctly to property changes and edits. Weitere Informationen finden Sie unter Implementieren von Benachrichtigungen bei Eigenschaftenänderungen.For more information, see Implement Property Change Notification.

    // Requires using System.Collections.ObjectModel;
    public class Tasks : ObservableCollection<Task>
    {
        // Creating the Tasks collection in this way enables data binding from XAML.
    }
    
    ' Requires Imports System.Collections.ObjectModel
    Public Class Tasks
        Inherits ObservableCollection(Of Task)
        ' Creating the Tasks collection in this way enables data binding from XAML.
    End Class
    
  2. Erstellen Sie in XAML eine Instanz der Collection-Klasse, und legen Sie die x:Key-Direktivefest.In XAML, create an instance of the collection class and set the x:Key Directive.

  3. Erstellen Sie in XAML eine Instanz der CollectionViewSource-Klasse, legen Sie die x:Key-Direktivefest, und legen Sie die Instanz der Auflistungs Klasse als Sourcefest.In XAML, create an instance of the CollectionViewSource class, set the x:Key Directive, and set the instance of your collection class as the Source.

    <Window.Resources>
        <local:Tasks x:Key="tasks" />
        <CollectionViewSource x:Key="cvsTasks" Source="{StaticResource tasks}" 
                              Filter="CollectionViewSource_Filter">
        </CollectionViewSource>    
    </Window.Resources>
    
  4. Erstellen Sie eine Instanz der DataGrid-Klasse, und legen Sie die ItemsSource-Eigenschaft auf die CollectionViewSourcefest.Create an instance of the DataGrid class, and set the ItemsSource property to the CollectionViewSource.

    <DataGrid x:Name="dataGrid1" 
              ItemsSource="{Binding Source={StaticResource cvsTasks}}"
              CanUserAddRows="False">
    
  5. Um auf die CollectionViewSource aus Ihrem Code zuzugreifen, verwenden Sie die GetDefaultView-Methode, um einen Verweis auf die CollectionViewSourcezu erhalten.To access the CollectionViewSource from your code, use the GetDefaultView method to get a reference to the CollectionViewSource.

    ICollectionView cvTasks = CollectionViewSource.GetDefaultView(dataGrid1.ItemsSource);
    
    Dim cvTasks As ICollectionView = CollectionViewSource.GetDefaultView(dataGrid1.ItemsSource)
    

Gruppieren von Elementen in einem DataGridGrouping items in a DataGrid

Um anzugeben, wie Elemente in einer DataGridgruppiert werden, verwenden Sie den PropertyGroupDescription-Typ, um die Elemente in der Quell Ansicht zu gruppieren.To specify how items are grouped in a DataGrid, you use the PropertyGroupDescription type to group the items in the source view.

So gruppieren Sie Elemente in einem DataGrid mithilfe von XAMLTo group items in a DataGrid using XAML

  1. Erstellen Sie einen PropertyGroupDescription, der die Eigenschaft angibt, nach der gruppiert werden soll.Create a PropertyGroupDescription that specifies the property to group by. Sie können die-Eigenschaft in XAML oder im Code angeben.You can specify the property in XAML or in code.

    1. Legen Sie in XAML die PropertyName auf den Namen der Eigenschaft fest, nach der gruppiert werden soll.In XAML, set the PropertyName to the name of the property to group by.

    2. Übergeben Sie im Code den Namen der Eigenschaft, die von Group by an den Konstruktor übergeben werden soll.In code, pass the name of the property to group by to the constructor.

  2. Fügen Sie die PropertyGroupDescription der CollectionViewSource.GroupDescriptions Auflistung hinzu.Add the PropertyGroupDescription to the CollectionViewSource.GroupDescriptions collection.

  3. Fügen Sie der GroupDescriptions Auflistung zusätzliche Instanzen von PropertyGroupDescription hinzu, um weitere Gruppierungs Ebenen hinzuzufügen.Add additional instances of PropertyGroupDescription to the GroupDescriptions collection to add more levels of grouping.

    <CollectionViewSource.GroupDescriptions>
        <PropertyGroupDescription PropertyName="ProjectName"/>
        <PropertyGroupDescription PropertyName="Complete"/>
    </CollectionViewSource.GroupDescriptions>
    
    ICollectionView cvTasks = CollectionViewSource.GetDefaultView(dataGrid1.ItemsSource);
    if (cvTasks != null && cvTasks.CanGroup == true)
    {
        cvTasks.GroupDescriptions.Clear();
        cvTasks.GroupDescriptions.Add(new PropertyGroupDescription("ProjectName"));
        cvTasks.GroupDescriptions.Add(new PropertyGroupDescription("Complete"));
    }
    
    Dim cvTasks As ICollectionView = CollectionViewSource.GetDefaultView(dataGrid1.ItemsSource)
    If cvTasks IsNot Nothing And cvTasks.CanGroup = True Then
        cvTasks.GroupDescriptions.Clear()
        cvTasks.GroupDescriptions.Add(New PropertyGroupDescription("ProjectName"))
        cvTasks.GroupDescriptions.Add(New PropertyGroupDescription("Complete"))
    End If
    
  4. Entfernen Sie die PropertyGroupDescription aus der GroupDescriptions Auflistung, um eine Gruppe zu entfernen.To remove a group, remove the PropertyGroupDescription from the GroupDescriptions collection.

  5. Um alle Gruppen zu entfernen, müssen Sie die Clear-Methode der GroupDescriptions Auflistung abrufen.To remove all groups, call the Clear method of the GroupDescriptions collection.

    ICollectionView cvTasks = CollectionViewSource.GetDefaultView(dataGrid1.ItemsSource);
    if (cvTasks != null)
    {
        cvTasks.GroupDescriptions.Clear();
    }
    
    Dim cvTasks As ICollectionView = CollectionViewSource.GetDefaultView(dataGrid1.ItemsSource)
    If cvTasks IsNot Nothing Then
        cvTasks.GroupDescriptions.Clear()
    End If
    

Wenn Elemente in der DataGridgruppiert werden, können Sie eine GroupStyle definieren, die die Darstellung der einzelnen Gruppen angibt.When items are grouped in the DataGrid, you can define a GroupStyle that specifies the appearance of each group. Sie wenden die GroupStyle an, indem Sie Sie der GroupStyle-Auflistung des DataGrid hinzufügen.You apply the GroupStyle by adding it to the GroupStyle collection of the DataGrid. Wenn Sie über mehrere Gruppierungs Ebenen verfügen, können Sie für jede Gruppenebene unterschiedliche Stile anwenden.If you have multiple levels of grouping, you can apply different styles to each group level. Stile werden in der Reihenfolge angewendet, in der Sie definiert sind.Styles are applied in the order in which they are defined. Wenn Sie z. b. zwei Stile definieren, wird die erste auf Zeilen Gruppen auf oberster Ebene angewendet.For example, if you define two styles, the first will be applied to top level row groups. Der zweite Stil wird auf alle Zeilen Gruppen auf der zweiten Ebene und niedriger angewendet.The second style will be applied to all row groups at the second level and lower. Der DataContext der GroupStyle ist die CollectionViewGroup, die die Gruppe darstellt.The DataContext of the GroupStyle is the CollectionViewGroup that the group represents.

So ändern Sie die Darstellung von Zeilen Gruppen HeadernTo change the appearance of row group headers

  1. Erstellen Sie eine GroupStyle, die die Darstellung der Zeilen Gruppe definiert.Create a GroupStyle that defines the appearance of the row group.

  2. Fügen Sie die GroupStyle in den <DataGrid.GroupStyle>-Tags ein.Put the GroupStyle inside the <DataGrid.GroupStyle> tags.

    <DataGrid.GroupStyle>
        <!-- Style for groups at top level. -->
        <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 IsExpanded="True" Background="#FF112255" BorderBrush="#FF002255" Foreground="#FFEEEEEE" BorderThickness="1,1,1,5">
                                    <Expander.Header>
                                        <DockPanel>
                                            <TextBlock FontWeight="Bold" Text="{Binding Path=Name}" Margin="5,0,0,0" Width="100"/>
                                            <TextBlock FontWeight="Bold" Text="{Binding Path=ItemCount}"/>
                                        </DockPanel>
                                    </Expander.Header>
                                    <Expander.Content>
                                        <ItemsPresenter />
                                    </Expander.Content>
                                </Expander>
                            </ControlTemplate>
                        </Setter.Value>
                    </Setter>
                </Style>
            </GroupStyle.ContainerStyle>
        </GroupStyle>
        <!-- Style for groups under the top level. -->
        <GroupStyle>
            <GroupStyle.HeaderTemplate>
                <DataTemplate>
                    <DockPanel Background="LightBlue">
                        <TextBlock Text="{Binding Path=Name, Converter={StaticResource completeConverter}}" Foreground="Blue" Margin="30,0,0,0" Width="100"/>
                        <TextBlock Text="{Binding Path=ItemCount}" Foreground="Blue"/>
                    </DockPanel>
                </DataTemplate>
            </GroupStyle.HeaderTemplate>
        </GroupStyle>
    </DataGrid.GroupStyle>
    

Sortieren von Elementen in einem DataGridSorting items in a DataGrid

Um anzugeben, wie Elemente in einer DataGridsortiert werden, verwenden Sie den SortDescription Typ, um die Elemente in der Quell Ansicht zu sortieren.To specify how items are sorted in a DataGrid, you use the SortDescription type to sort the items in the source view.

So sortieren Sie Elemente in einem DataGridTo sort items in a DataGrid

  1. Erstellen Sie einen SortDescription, der die Eigenschaft angibt, nach der sortiert werden soll.Create a SortDescription that specifies the property to sort by. Sie können die-Eigenschaft in XAML oder im Code angeben.You can specify the property in XAML or in code.

    1. Legen Sie in XAML die PropertyName auf den Namen der Eigenschaft fest, nach der sortiert werden soll.In XAML, set the PropertyName to the name of the property to sort by.

    2. Übergeben Sie im Code den Namen der Eigenschaft, nach der sortiert werden soll, und die ListSortDirection an den Konstruktor.In code, pass the name of the property to sort by and the ListSortDirection to the constructor.

  2. Fügen Sie die SortDescription der CollectionViewSource.SortDescriptions Auflistung hinzu.Add the SortDescription to the CollectionViewSource.SortDescriptions collection.

  3. Fügen Sie der SortDescriptions Auflistung zusätzliche Instanzen von SortDescription hinzu, um nach zusätzlichen Eigenschaften zu sortieren.Add additional instances of SortDescription to the SortDescriptions collection to sort by additional properties.

    <CollectionViewSource.SortDescriptions>
        <!-- Requires 'xmlns:scm="clr-namespace:System.ComponentModel;assembly=WindowsBase"' declaration. -->
        <scm:SortDescription PropertyName="ProjectName"/>
        <scm:SortDescription PropertyName="Complete" />
        <scm:SortDescription PropertyName="DueDate" />
    </CollectionViewSource.SortDescriptions>
    
    // Requires using System.ComponentModel;
    ICollectionView cvTasks = CollectionViewSource.GetDefaultView(dataGrid1.ItemsSource);
    if (cvTasks != null && cvTasks.CanSort == true)
    {
        cvTasks.SortDescriptions.Clear();
        cvTasks.SortDescriptions.Add(new SortDescription("ProjectName", ListSortDirection.Ascending));
        cvTasks.SortDescriptions.Add(new SortDescription("Complete", ListSortDirection.Ascending));
        cvTasks.SortDescriptions.Add(new SortDescription("DueDate", ListSortDirection.Ascending));
    }
    
    Dim cvTasks As ICollectionView = CollectionViewSource.GetDefaultView(dataGrid1.ItemsSource)
    If cvTasks IsNot Nothing And cvTasks.CanSort = True Then
        cvTasks.SortDescriptions.Clear()
        cvTasks.SortDescriptions.Add(New SortDescription("ProjectName", ListSortDirection.Ascending))
        cvTasks.SortDescriptions.Add(New SortDescription("Complete", ListSortDirection.Ascending))
        cvTasks.SortDescriptions.Add(New SortDescription("DueDate", ListSortDirection.Ascending))
    End If
    

Filtern von Elementen in einem DataGridFiltering items in a DataGrid

Um Elemente in einer DataGrid mithilfe eines CollectionViewSourcezu filtern, stellen Sie die Filter Logik im-Handler für das CollectionViewSource.Filter-Ereignis bereit.To filter items in a DataGrid using a CollectionViewSource, you provide the filtering logic in the handler for the CollectionViewSource.Filter event.

So filtern Sie Elemente in einem DataGrid-SteuerelementTo filter items in a DataGrid

  1. Fügen Sie einen Handler für das CollectionViewSource.Filter-Ereignis hinzu.Add a handler for the CollectionViewSource.Filter event.

  2. Definieren Sie im Filter-Ereignishandler die Filter Logik.In the Filter event handler, define the filtering logic.

    Der Filter wird jedes Mal angewendet, wenn die Ansicht aktualisiert wird.The filter will be applied every time the view is refreshed.

    <CollectionViewSource x:Key="cvsTasks" Source="{StaticResource tasks}" 
                          Filter="CollectionViewSource_Filter">
    
    private void CollectionViewSource_Filter(object sender, FilterEventArgs e)
    {
        Task t = e.Item as Task;
        if (t != null)
        // If filter is turned on, filter completed items.
        {
            if (this.cbCompleteFilter.IsChecked == true && t.Complete == true)
                e.Accepted = false;
            else
                e.Accepted = true;
        }
    }
    
    Private Sub CollectionViewSource_Filter(ByVal sender As System.Object, ByVal e As System.Windows.Data.FilterEventArgs)
        Dim t As Task = e.Item
        If t IsNot Nothing Then
            ' If filter is turned on, filter completed items.
            If Me.cbCompleteFilter.IsChecked = True And t.Complete = True Then
                e.Accepted = False
            Else
                e.Accepted = True
            End If
        End If
    End Sub
    

Alternativ können Sie Elemente in einer DataGrid filtern, indem Sie eine Methode erstellen, die die Filter Logik bereitstellt, und die CollectionView.Filter-Eigenschaft festlegen, um den Filter anzuwenden.Alternatively, you can filter items in a DataGrid by creating a method that provides the filtering logic and setting the CollectionView.Filter property to apply the filter. Ein Beispiel für diese Methode finden Sie unter Filtern von Daten in einer Ansicht.To see an example of this method, see Filter Data in a View.

BeispielExample

Das folgende Beispiel veranschaulicht das Gruppieren, Sortieren und Filtern von Task Daten in einer CollectionViewSource und das Anzeigen der gruppierten, sortierten und gefilterten Task Daten in einem DataGrid.The following example demonstrates grouping, sorting, and filtering Task data in a CollectionViewSource and displaying the grouped, sorted, and filtered Task data in a DataGrid. Der CollectionViewSource wird als ItemsSource für die DataGridverwendet.The CollectionViewSource is used as the ItemsSource for the DataGrid. Gruppieren, Sortieren und Filtern werden auf dem CollectionViewSource ausgeführt und in der DataGrid-Benutzeroberfläche angezeigt.Grouping, sorting, and filtering are performed on the CollectionViewSource and are displayed in the DataGrid UI.

Zum Testen dieses Beispiels müssen Sie den dggroupsortfilterexample-Namen entsprechend Ihrem Projektnamen anpassen.To test this example, you will need to adjust the DGGroupSortFilterExample name to match your project name. Wenn Sie Visual Basic verwenden, müssen Sie den Klassennamen für Window wie folgt ändern.If you are using Visual Basic, you will need to change the class name for Window to the following.

<Window x:Class="MainWindow"

<Window x:Class="DGGroupSortFilterExample.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:DGGroupSortFilterExample"
        xmlns:scm="clr-namespace:System.ComponentModel;assembly=WindowsBase"
        Title="Group, Sort, and Filter Example" Height="575" Width="525">
    <Window.Resources>
        <local:CompleteConverter x:Key="completeConverter" />
        <local:Tasks x:Key="tasks" />
        <CollectionViewSource x:Key="cvsTasks" Source="{StaticResource tasks}" 
                              Filter="CollectionViewSource_Filter">
            <CollectionViewSource.SortDescriptions>
                <!-- Requires 'xmlns:scm="clr-namespace:System.ComponentModel;assembly=WindowsBase"' declaration. -->
                <scm:SortDescription PropertyName="ProjectName"/>
                <scm:SortDescription PropertyName="Complete" />
                <scm:SortDescription PropertyName="DueDate" />
            </CollectionViewSource.SortDescriptions>
            <CollectionViewSource.GroupDescriptions>
                <PropertyGroupDescription PropertyName="ProjectName"/>
                <PropertyGroupDescription PropertyName="Complete"/>
            </CollectionViewSource.GroupDescriptions>
        </CollectionViewSource>
    </Window.Resources>
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition />
            <RowDefinition Height="30" />
        </Grid.RowDefinitions>
        <DataGrid x:Name="dataGrid1" 
                  ItemsSource="{Binding Source={StaticResource cvsTasks}}"
                  CanUserAddRows="False">
            <DataGrid.GroupStyle>
                <!-- Style for groups at top level. -->
                <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 IsExpanded="True" Background="#FF112255" BorderBrush="#FF002255" Foreground="#FFEEEEEE" BorderThickness="1,1,1,5">
                                            <Expander.Header>
                                                <DockPanel>
                                                    <TextBlock FontWeight="Bold" Text="{Binding Path=Name}" Margin="5,0,0,0" Width="100"/>
                                                    <TextBlock FontWeight="Bold" Text="{Binding Path=ItemCount}"/>
                                                </DockPanel>
                                            </Expander.Header>
                                            <Expander.Content>
                                                <ItemsPresenter />
                                            </Expander.Content>
                                        </Expander>
                                    </ControlTemplate>
                                </Setter.Value>
                            </Setter>
                        </Style>
                    </GroupStyle.ContainerStyle>
                </GroupStyle>
                <!-- Style for groups under the top level. -->
                <GroupStyle>
                    <GroupStyle.HeaderTemplate>
                        <DataTemplate>
                            <DockPanel Background="LightBlue">
                                <TextBlock Text="{Binding Path=Name, Converter={StaticResource completeConverter}}" Foreground="Blue" Margin="30,0,0,0" Width="100"/>
                                <TextBlock Text="{Binding Path=ItemCount}" Foreground="Blue"/>
                            </DockPanel>
                        </DataTemplate>
                    </GroupStyle.HeaderTemplate>
                </GroupStyle>
            </DataGrid.GroupStyle>
            <DataGrid.RowStyle>
                <Style TargetType="DataGridRow">
                    <Setter Property="Foreground" Value="Black" />
                    <Setter Property="Background" Value="White" />
                </Style>
            </DataGrid.RowStyle>
        </DataGrid>
        <StackPanel Orientation="Horizontal" Grid.Row="1">
            <TextBlock Text=" Filter completed items " VerticalAlignment="Center" />
            <CheckBox x:Name="cbCompleteFilter" VerticalAlignment="Center"
                      Checked="CompleteFilter_Changed" Unchecked="CompleteFilter_Changed" />
            <Button Content="Remove Groups" Margin="10,2,2,2" Click="UngroupButton_Click" />
            <Button Content="Group by Project/Status" Margin="2" Click="GroupButton_Click" />
        </StackPanel>
    </Grid>
</Window>
using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Windows;
using System.Windows.Data;

namespace DGGroupSortFilterExample
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            
            // Get a reference to the tasks collection.
            Tasks _tasks = (Tasks)this.Resources["tasks"];

            // Generate some task data and add it to the task list.
            for (int i = 1; i <= 14; i++)
            {
                _tasks.Add(new Task()
                {
                    ProjectName = "Project " + ((i % 3) + 1).ToString(),
                    TaskName = "Task " + i.ToString(),
                    DueDate = DateTime.Now.AddDays(i),
                    Complete = (i % 2 == 0)
                });
            }
        }
        
        private void UngroupButton_Click(object sender, RoutedEventArgs e)
        {
            ICollectionView cvTasks = CollectionViewSource.GetDefaultView(dataGrid1.ItemsSource);
            if (cvTasks != null)
            {
                cvTasks.GroupDescriptions.Clear();
            }
        }
        
        private void GroupButton_Click(object sender, RoutedEventArgs e)
        {
            ICollectionView cvTasks = CollectionViewSource.GetDefaultView(dataGrid1.ItemsSource);
            if (cvTasks != null && cvTasks.CanGroup == true)
            {
                cvTasks.GroupDescriptions.Clear();
                cvTasks.GroupDescriptions.Add(new PropertyGroupDescription("ProjectName"));
                cvTasks.GroupDescriptions.Add(new PropertyGroupDescription("Complete"));
            }
        }
        
        private void CompleteFilter_Changed(object sender, RoutedEventArgs e)
        {
            // Refresh the view to apply filters.
            CollectionViewSource.GetDefaultView(dataGrid1.ItemsSource).Refresh();
        }

        private void CollectionViewSource_Filter(object sender, FilterEventArgs e)
        {
            Task t = e.Item as Task;
            if (t != null)
            // If filter is turned on, filter completed items.
            {
                if (this.cbCompleteFilter.IsChecked == true && t.Complete == true)
                    e.Accepted = false;
                else
                    e.Accepted = true;
            }
        }
    }

    [ValueConversion(typeof(Boolean), typeof(String))]
    public class CompleteConverter : IValueConverter
    {
        // This converter changes the value of a Tasks Complete status from true/false to a string value of
        // "Complete"/"Active" for use in the row group header.
        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            bool complete = (bool)value;
            if (complete)
                return "Complete";
            else
                return "Active";
        }

        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            string strComplete = (string)value;
            if (strComplete == "Complete")
                return true;
            else
                return false;
        }
    }

    // Task Class
    // Requires using System.ComponentModel;
    public class Task : INotifyPropertyChanged, IEditableObject
    {
        // The Task class implements INotifyPropertyChanged and IEditableObject 
        // so that the datagrid can properly respond to changes to the 
        // data collection and edits made in the DataGrid.

        // Private task data.
        private string m_ProjectName = string.Empty;
        private string m_TaskName = string.Empty;
        private DateTime m_DueDate = DateTime.Now;
        private bool m_Complete = false;

        // Data for undoing canceled edits.
        private Task temp_Task = null;
        private bool m_Editing = false;

        // Public properties. 
        public string ProjectName
        {
            get { return this.m_ProjectName; }
            set
            {
                if (value != this.m_ProjectName)
                {
                    this.m_ProjectName = value;
                    NotifyPropertyChanged("ProjectName");
                }
            }
        }

        public string TaskName
        {
            get { return this.m_TaskName; }
            set
            {
                if (value != this.m_TaskName)
                {
                    this.m_TaskName = value;
                    NotifyPropertyChanged("TaskName");
                }
            }
        }

        public DateTime DueDate
        {
            get { return this.m_DueDate; }
            set
            {
                if (value != this.m_DueDate)
                {
                    this.m_DueDate = value;
                    NotifyPropertyChanged("DueDate");
                }
            }
        }

        public bool Complete
        {
            get { return this.m_Complete; }
            set
            {
                if (value != this.m_Complete)
                {
                    this.m_Complete = value;
                    NotifyPropertyChanged("Complete");
                }
            }
        }

        // Implement INotifyPropertyChanged interface.
        public event PropertyChangedEventHandler PropertyChanged;

        private void NotifyPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }

        // Implement IEditableObject interface.
        public void BeginEdit()
        {
            if (m_Editing == false)
            {
                temp_Task = this.MemberwiseClone() as Task;
                m_Editing = true;
            }
        }

        public void CancelEdit()
        {
            if (m_Editing == true)
            {
                this.ProjectName = temp_Task.ProjectName;
                this.TaskName = temp_Task.TaskName;
                this.DueDate = temp_Task.DueDate;
                this.Complete = temp_Task.Complete;
                m_Editing = false;
            }
        }

        public void EndEdit()
        {
            if (m_Editing == true)
            {
                temp_Task = null;
                m_Editing = false;
            }
        }
    }
    // Requires using System.Collections.ObjectModel;
    public class Tasks : ObservableCollection<Task>
    {
        // Creating the Tasks collection in this way enables data binding from XAML.
    }
}
Imports System.ComponentModel
Imports System.Collections.ObjectModel

Class MainWindow
    Public Sub New()
        InitializeComponent()

        ' Get a reference to the tasks collection.
        Dim _tasks As Tasks = Me.Resources("tasks")

        ' Generate some task data and add it to the task list.
        For index = 1 To 14
            _tasks.Add(New Task() With _
                         {.ProjectName = "Project " & ((index Mod 3) + 1).ToString(), _
                           .TaskName = "Task " & index.ToString(), _
                           .DueDate = Date.Now.AddDays(index), _
                           .Complete = (index Mod 2 = 0) _
                         })
        Next
    End Sub

    Private Sub UngroupButton_Click(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs)
        Dim cvTasks As ICollectionView = CollectionViewSource.GetDefaultView(dataGrid1.ItemsSource)
        If cvTasks IsNot Nothing Then
            cvTasks.GroupDescriptions.Clear()
        End If
    End Sub

    Private Sub GroupButton_Click(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs)
        Dim cvTasks As ICollectionView = CollectionViewSource.GetDefaultView(dataGrid1.ItemsSource)
        If cvTasks IsNot Nothing And cvTasks.CanGroup = True Then
            cvTasks.GroupDescriptions.Clear()
            cvTasks.GroupDescriptions.Add(New PropertyGroupDescription("ProjectName"))
            cvTasks.GroupDescriptions.Add(New PropertyGroupDescription("Complete"))
        End If
    End Sub

    Private Sub CompleteFilter_Changed(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs)
        ' Refresh the view to apply filters.
        CollectionViewSource.GetDefaultView(dataGrid1.ItemsSource).Refresh()
    End Sub

    Private Sub CollectionViewSource_Filter(ByVal sender As System.Object, ByVal e As System.Windows.Data.FilterEventArgs)
        Dim t As Task = e.Item
        If t IsNot Nothing Then
            ' If filter is turned on, filter completed items.
            If Me.cbCompleteFilter.IsChecked = True And t.Complete = True Then
                e.Accepted = False
            Else
                e.Accepted = True
            End If
        End If
    End Sub
End Class

Public Class CompleteConverter
    Implements IValueConverter
    ' This converter changes the value of a Tasks Complete status from true/false to a string value of
    ' "Complete"/"Active" for use in the row group header.
    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
        Dim complete As Boolean = value
        If complete = True Then
            Return "Complete"
        Else
            Return "Active"
        End If
    End Function

    Public Function ConvertBack1(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
        Dim strComplete As String = value
        If strComplete = "Complete" Then
            Return True
        Else
            Return False
        End If
    End Function
End Class

' Task class
' Requires Imports System.ComponentModel
Public Class Task
    Implements INotifyPropertyChanged, IEditableObject
    ' The Task class implements INotifyPropertyChanged and IEditableObject 
    ' so that the datagrid can properly respond to changes to the 
    ' data collection and edits made in the DataGrid.

    ' Private task data.
    Private m_ProjectName As String = String.Empty
    Private m_TaskName As String = String.Empty
    Private m_DueDate As DateTime = Date.Now
    Private m_Complete As Boolean = False

    ' Data for undoing canceled edits.
    Private temp_Task As Task = Nothing
    Private m_Editing As Boolean = False

    ' Public properties.
    Public Property ProjectName() As String
        Get
            Return Me.m_ProjectName
        End Get
        Set(ByVal value As String)
            If Not value = Me.m_ProjectName Then
                Me.m_ProjectName = value
                NotifyPropertyChanged("ProjectName")
            End If
        End Set
    End Property

    Public Property TaskName() As String
        Get
            Return Me.m_TaskName
        End Get
        Set(ByVal value As String)
            If Not value = Me.m_TaskName Then
                Me.m_TaskName = value
                NotifyPropertyChanged("TaskName")
            End If
        End Set
    End Property

    Public Property DueDate() As Date
        Get
            Return Me.m_DueDate
        End Get
        Set(ByVal value As Date)
            If Not value = Me.m_DueDate Then
                Me.m_DueDate = value
                NotifyPropertyChanged("DueDate")
            End If
        End Set
    End Property

    Public Property Complete() As Boolean
        Get
            Return Me.m_Complete
        End Get
        Set(ByVal value As Boolean)
            If Not value = Me.m_Complete Then
                Me.m_Complete = value
                NotifyPropertyChanged("Complete")
            End If
        End Set
    End Property

    ' Implement INotifyPropertyChanged interface. 
    Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged

    Public Sub NotifyPropertyChanged(ByVal propertyName As String)
        RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(propertyName))
    End Sub

    ' Implement IEditableObject interface.
    Public Sub BeginEdit() Implements IEditableObject.BeginEdit
        If Not Me.m_Editing Then
            Me.temp_Task = Me.MemberwiseClone()
            Me.m_Editing = True
        End If
    End Sub

    Public Sub CancelEdit() Implements IEditableObject.CancelEdit
        If m_Editing = True Then
            Me.ProjectName = Me.temp_Task.ProjectName
            Me.TaskName = Me.temp_Task.TaskName
            Me.DueDate = Me.temp_Task.DueDate
            Me.Complete = Me.temp_Task.Complete
            Me.m_Editing = False
        End If
    End Sub

    Public Sub EndEdit() Implements IEditableObject.EndEdit
        If m_Editing = True Then
            Me.temp_Task = Nothing
            Me.m_Editing = False
        End If
    End Sub
End Class

' Requires Imports System.Collections.ObjectModel
Public Class Tasks
    Inherits ObservableCollection(Of Task)
    ' Creating the Tasks collection in this way enables data binding from XAML.
End Class

Siehe auchSee also