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

Es ist häufig nützlich zum Anzeigen von Daten in einem DataGrid auf verschiedene Arten von gruppieren, Sortieren und Filtern der Daten.It is often useful to view data in a DataGrid in different ways by grouping, sorting, and filtering the data. Zu gruppieren, Sortieren und Filtern der Daten in einem DataGrid, binden Sie es an eine CollectionView , die diese Funktionen unterstützt.To group, sort, and filter the data in a DataGrid, you bind it to a CollectionView that supports these functions. Anschließend können Sie arbeiten mit den Daten in die CollectionView ohne Auswirkungen auf die zugrunde liegenden Daten.You can then work with the data in the CollectionView without affecting the underlying source data. Die Änderungen in der Auflistungsansicht werden angezeigt, der DataGrid Benutzeroberfläche (UI).The changes in the collection view are reflected in the DataGrid user interface (UI).

Die CollectionView Klasse enthält, gruppieren und Sortieren von Funktionen für eine Datenquelle, die implementiert die IEnumerable Schnittstelle.The CollectionView class provides grouping and sorting functionality for a data source that implements the IEnumerable interface. Die CollectionViewSource -Klasse können Sie zum Festlegen der Eigenschaften von einem CollectionView aus XAML.The CollectionViewSource class enables you to set the properties of a CollectionView from XAML.

In diesem Beispiel ist eine Auflistung von Task Objekte gebunden ist, um eine CollectionViewSource.In this example, a collection of Task objects is bound to a CollectionViewSource. Die CollectionViewSource dient als die ItemsSource für die DataGrid.The CollectionViewSource is used as the ItemsSource for the DataGrid. Gruppierung, Sortierung und Filterung werden ausgeführt, auf die CollectionViewSource und werden angezeigt, der DataGrid Benutzeroberfläche.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 eine Bindung zu CollectionViewSource als ItemsSourceUsing a CollectionViewSource as an ItemsSource

Zu gruppieren, Sortieren und Filtern von Daten in eine DataGrid -Steuerelement binden Sie die DataGrid zu einem 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 die DataGrid gebunden ist eine CollectionViewSource , die diese Funktionen für bietet ein List<T> von Task Objekte.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-Steuerelement an eine Bindung zu CollectionViewSourceTo bind a DataGrid to a CollectionViewSource

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

    Bei Verwendung von List<T> um Ihrer Sammlung zu erstellen, erstellen Sie eine neue Klasse, die von erbt List<T> zu eine Instanz von instanziieren, sondern List<T>.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>. Dadurch können Sie für die Datenbindung an die Sammlung in XAML.This enables you to data bind to the collection in XAML.

    Hinweis

    Die Objekte in der Auflistung müssen implementieren die INotifyPropertyChanged geänderte Schnittstelle und die IEditableObject Schnittstelle in der Reihenfolge für die DataGrid ordnungsgemäß auf eigenschaftenänderungen und Änderungen zu reagieren.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. Klicken Sie in XAML, erstellen Sie eine Instanz der Auflistungsklasse, und legen Sie die X: Key Directive.In XAML, create an instance of the collection class and set the x:Key Directive.

  3. In XAML, erstellen Sie eine Instanz von der CollectionViewSource Klasse, legen die X: Key Directive, und legen Sie die Instanz der Auflistungsklasse als die Source.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 von der DataGrid Klasse, und legen die ItemsSource Eigenschaft, um die CollectionViewSource.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. Für den Zugriff auf die CollectionViewSource aus Ihrem Code verwendet die GetDefaultView Methode zum Abrufen eines Verweises auf die CollectionViewSource.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 gruppiert sind, in eine DataGrid, Sie verwenden die PropertyGroupDescription Typ Gruppierung der Elemente in der Datenquellensicht.To specify how items are grouped in a DataGrid, you use the PropertyGroupDescription type to group the items in the source view.

Die Gruppierung der Elemente in einem DataGrid mit XAMLTo group items in a DataGrid using XAML

  1. Erstellen Sie eine PropertyGroupDescription , der die Eigenschaft für die Gruppierung angibt.Create a PropertyGroupDescription that specifies the property to group by. Sie können die Eigenschaft in XAML oder Code angeben.You can specify the property in XAML or in code.

    1. In XAML, Festlegen der PropertyName auf den Namen der Eigenschaft nach der gruppiert werden.In XAML, set the PropertyName to the name of the property to group by.

    2. Im Code müssen übergeben Sie den Namen der Eigenschaft an Gruppieren nach an den Konstruktor.In code, pass the name of the property to group by to the constructor.

  2. Hinzufügen der PropertyGroupDescription auf die CollectionViewSource.GroupDescriptions Auflistung.Add the PropertyGroupDescription to the CollectionViewSource.GroupDescriptions collection.

  3. Fügen Sie zusätzliche Instanzen PropertyGroupDescription auf die GroupDescriptions mehr Gruppierungsebenen hinzuzufügende Auflistung.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. Um eine Gruppe zu entfernen, entfernen die PropertyGroupDescription aus der GroupDescriptions Auflistung.To remove a group, remove the PropertyGroupDescription from the GroupDescriptions collection.

  5. Um alle Gruppen zu entfernen, rufen Sie die Clear Methode der GroupDescriptions Auflistung.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 gruppiert werden, der DataGrid, können Sie definieren eine GroupStyle , 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 gelten die GroupStyle fügen es zu der GroupStyle Auflistung von das DataGrid-Steuerelement.You apply the GroupStyle by adding it to the GroupStyle collection of the DataGrid. Wenn Sie mehrere Gruppierungsebenen verfügen, können Sie verschiedene Formate auf jede Gruppierungsebene anwenden.If you have multiple levels of grouping, you can apply different styles to each group level. Stile werden in der Reihenfolge angewendet, in denen sie definiert sind.Styles are applied in the order in which they are defined. Wenn Sie zwei Formate definieren, wird z. B. die erste auf oberste Ebene Zeilengruppen angewendet werden.For example, if you define two styles, the first will be applied to top level row groups. Das zweite Format werden für alle Zeilengruppen auf der zweiten Ebene übernommen und niedriger.The second style will be applied to all row groups at the second level and lower. Die DataContext von 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 der zeilengruppenüberschriftenTo change the appearance of row group headers

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

  2. Platzieren der GroupStyle innerhalb der <DataGrid.GroupStyle> Tags.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 sortiert werden, in eine DataGrid, Sie verwenden die SortDescription Typ zum Sortieren der Elemente in der Datenquellensicht.To specify how items are sorted in a DataGrid, you use the SortDescription type to sort the items in the source view.

Zum Sortieren der Elemente in einem DataGridTo sort items in a DataGrid

  1. Erstellen Sie eine SortDescription , die Eigenschaft angibt, nach zu sortieren.Create a SortDescription that specifies the property to sort by. Sie können die Eigenschaft in XAML oder Code angeben.You can specify the property in XAML or in code.

    1. In XAML, Festlegen der PropertyName auf den Namen der Eigenschaft, die nach zu sortieren.In XAML, set the PropertyName to the name of the property to sort by.

    2. Im Code übergeben, den Namen der Eigenschaft, die nach zu sortieren und die ListSortDirection an den Konstruktor.In code, pass the name of the property to sort by and the ListSortDirection to the constructor.

  2. Hinzufügen der SortDescription auf die CollectionViewSource.SortDescriptions Auflistung.Add the SortDescription to the CollectionViewSource.SortDescriptions collection.

  3. Fügen Sie zusätzliche Instanzen SortDescription auf die SortDescriptions -Auflistung, 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

Zum Filtern von Elementen in eine DataGrid mit einer CollectionViewSource, geben Sie die Filterlogik im Ereignishandler für die CollectionViewSource.Filter Ereignis.To filter items in a DataGrid using a CollectionViewSource, you provide the filtering logic in the handler for the CollectionViewSource.Filter event.

Zum Filtern von Elementen in einem DataGridTo filter items in a DataGrid

  1. Hinzufügen eines ereignishandlers für das CollectionViewSource.Filter Ereignis.Add a handler for the CollectionViewSource.Filter event.

  2. In der Filter -Ereignishandler definieren Sie die Filterlogik.In the Filter event handler, define the filtering logic.

    Jedes Mal, wenn die Ansicht aktualisiert wird, wird der Filter angewendet werden.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 Filtern von Elementen in einem DataGrid durch Erstellen einer Methode, die die Filterung Logik und die Einstellung bietet die CollectionView.Filter Eigenschaft, 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 dieser 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 die Gruppierung, Sortierung und Filterung Task Daten in eine CollectionViewSource und 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. Die CollectionViewSource dient als die ItemsSource für die DataGrid.The CollectionViewSource is used as the ItemsSource for the DataGrid. Gruppierung, Sortierung und Filterung werden ausgeführt, auf die CollectionViewSource und werden angezeigt, der DataGrid Benutzeroberfläche.Grouping, sorting, and filtering are performed on the CollectionViewSource and are displayed in the DataGrid UI.

Zum Testen dieses Beispiels müssen Sie den Namen "DGGroupSortFilterExample" entsprechend Ihren Projektnamen entsprechend 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 so ändern Sie den Klassennamen für Window folgt.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