Главная » WPF » Фильтрация, сортировка и группировка

0

Фильтрация – самая простая из всех функций представления; мы определяем об ратный вызов в виде делегата, который решает, надо ли показывать  элемент набора. Как всегда, можно воспользоваться представлением по умолчанию, модифицировать его или создать новое. Чтобы стало понятно, как обрабатываются элементы, возьмем два списка: один с подразумеваемым представлением (немодифицированным), а другой – со специальным представлением, в котором реализованы некие хитрости.

Сначала создадим собственное представление, которое отфильтровывает всех носящих имя Don:

ICollectionView view = new ListCollectionView(names);

view.Filter =

delegate(object item) {

return ((Person)item).Name.First != «Don»;

};

Рис. 6.18. Фильтрация элементов списка

Чтобы показать это представление, запишем его в свойство ItemsSource спис

ка. На рис. 6.18 показано, что в результате  из списка удаляется  один элемент:

public class CollectionViews : Window {

public CollectionViews() {

StackPanel sp = new StackPanel(); Person[] names = new Person[] {

new Person(new Name(«Chris», «Anderson»)), new Person(new Name(«Don», «Box»)),

new Person(new Name(«Chris», «Sells»)),

new Person(new Name(«Brent», «Anderson»)), new Person(new Name(«Dave», «Sells»)),

};

sp.Children.Add(new TextBlock(new Run(«Unmodified»))); ListBox list = new ListBox();

list.DisplayMemberPath = «Name»; list.ItemsSource = names; sp.Children.Add(list);

sp.Children.Add(new TextBlock(new Run(«Modified»))); ListBox modified = new ListBox();

ICollectionView view = new ListCollectionView(names);

view.Filter =

delegate(object item) {

return ((Person)item).Name.First != «Don»;

};

modified.DisplayMemberPath = «Name»; modified.ItemsSource = view; sp.Children.Add(modified);

Content = sp;

}

}

Сортировка также не вызывает трудностей. Добавив один или несколько объектов SortDescription, мы сможем отсортировать список по любому числу свойств. В приме ре ниже сортировка производится сначала по фамилии, а потом по имени (рис. 6.19):

view.SortDescriptions.Add(

new SortDescription(«Name.Last», ListSortDirection.Ascending));

view.SortDescriptions.Add(

new SortDescription(«Name.First», ListSortDirection.Ascending));

Последняя функция – группировка – нуждается  в поддержке как со стороны представления набора, так и со стороны элемента управления, который привязы вается  к данным.  С точки  зрения  представления набора  группировка работает почти так же, как сортировка: мы добавляем один или несколько объектов GroupDescription, которые определяют,  как данные разбиваются на группы:

view.GroupDescriptions.Add(new PropertyGroupDescription(«Name.Last»));

Рис. 6.19. Сортировка данных в представлении

На стороне же элемента управления необходим какой то способ визуализиро вать группы. Все списковые  элементы  управления в WPF обладают  свойством GroupStyle, которое предназначено как раз для этой цели (рис. 6.20):

GroupStyle style = new GroupStyle();

style.HeaderTemplate = new DataTemplate();

style.HeaderTemplate.VisualTree =

new FrameworkElementFactory(typeof(TextBlock));

style.HeaderTemplate.VisualTree.SetBinding( TextBlock.TextProperty, new Binding(«Name»));

style.HeaderTemplate.VisualTree.SetValue( TextBlock.BackgroundProperty, Brushes.Silver);

modified.GroupStyle.Add(style);

Рис. 6.20. Группировка данных в представлении

В этом примере  мы применили класс PropertyGroupDescription, который  оп ределяет группировку на базе значения  некоторого  свойства. Не слишком  слож но самостоятельно реализовать логику группировки, унаследовав классу GroupDescription и переопределив метод GroupNameFromItem.

Преобразование всего этого в разметку  производится в общем то прямоли нейно, но есть несколько  интересных  подводных  камней. Чтобы  описать предс тавление набора в разметке, необходимо использовать тип CollectionViewSource:

<Window …

Title=’EssentialWPF’

<Window.Resources>

<CollectionViewSource x:Key=’customView’ />

</Window.Resources>

</Window>

Чтобы привязать данные к представлению набора в качестве источника,  мы должны установить свойство Source. Следуя духу исходного примера, опишем источник как массив объектов типа Person. Зададим  также контекст данных для окна:

<Window …

xmlns:l=’clr namespace:EssentialWPF’ Title=’EssentialWPF’ DataContext=’{DynamicResource dataSource}’

<Window.Resources>

<x:Array Type=’{x:Type l:Person}’ x:Key=’dataSource’>

<l:Person>

<l:Person.Name>

<l:Name First=’Chris’ Last=’Anderson’ />

</l:Person.Name>

</l:Person>

<!— прочие люди —>

</x:Array>

<CollectionViewSource x:Key=’customView’ Source=’{StaticResource dataSource}’ />

</Window.Resources>

</Window>

Для присваивания значения свойству Source необходимо использовать стати ческий  ресурс StaticResource, так как это свойство  не является зависимым. Но для задания  свойства  DataContext для окна мы в этом случае обязаны  пользо ваться  динамическим ресурсом  DynamicResource, так  как  определение dataSource находится  внутри окна (DynamicResource допускает такого рода опе режающие  ссылки).  Для  фильтрации CollectionViewSource применяется собы тие, а не простой  обратный  вызов через делегата, поэтому придется  немного из менить определение  фильтра  на C#:

public void NotDon(object sender, FilterEventArgs e) {

e.Accepted = ((Person)e.Item).Name.First != «Don»;

}

Теперь  добавление  фильтра  сводится  просто  к присоединению обработчика события к источнику  CollectionViewSource:

<CollectionViewSource x:Key=’customView’

Filter=’NotDon’

Source=’{StaticResource dataSource}’ />

Сортировка осложняется только тем фактом, что класс SortDescription опре делен в пространстве  имен System.ComponentModel, которое обычно не включа ется в стандартную  для WPF директиву  xmlns:

<CollectionViewSource x:Key=’customView’

xmlns:cm=’clr namespace:System.ComponentModel;assembly=WindowsBase’

Filter=’NotDon’ Source=’{StaticResource dataSource}’>

<CollectionViewSource.SortDescriptions>

<cm:SortDescription PropertyName=’Name.Last’ Direction=’Ascending’ />

<cm:SortDescription PropertyName=’Name.First’ Direction=’Ascending’ />

</CollectionViewSource.SortDescriptions>

</CollectionViewSource>

Группировка описывается тривиально, никаких расхождений с ожиданиями нет:

<CollectionViewSource x:Key=’customView’ … >

<CollectionViewSource.GroupDescriptions>

<PropertyGroupDescription PropertyName=’Name.Last’ />

</CollectionViewSource.GroupDescriptions>

</CollectionViewSource>

Списковое  поле привязывается к представлению набора через стандартное свойство  ItemsSource. Кстати,  хотя  представление можно  использовать напря мую как значение свойства ItemsSource, для привязки к нему в качестве источни ка необходим объект Binding:

<ListBox DisplayMemberPath=’Name’

ItemsSource=’{Binding Source={StaticResource customView}}’>

<ListBox.GroupStyle>

<GroupStyle HeaderTemplate=’{StaticResource groupHeader}’ />

</ListBox.GroupStyle>

</ListBox>

Представления наборов обеспечивают  эффективное обобществление данных, а также различные виды данных. Использовать их во всех сценариях  привязки необязательно, но при правильном применении они могут заметно повысить про изводительность приложения.

Источник: К. Андерсон  Основы  Windows Presentation Foundation. Пер. с англ. А. Слинкина — М.: ДМК Пресс, 2008 — 432 с.: ил.

По теме:

  • Комментарии