Главная » Разработка для Windows Phone 7 » Сортировка Windows Phone 7

0

Ранее при выводе на экран данных об учащихся для отображения имени учащегося использовалось свойство FullName класса Student. Можно заметить, что файл students.xml сортирован по этому свойству, и именно в этом порядке данные учащихся выводятся на экран. Все популярные приложения для электронной почты сортируют контакты по имени, поэтому такой вариант мне показался вполне подходящим.

Но в только что рассмотренном нами DataTemplate используются свойства LastName (Фамилия), FirstName и MiddleName (Второе имя). Это приводит к выводу несортированных данных, что выглядит странным и просто неправильным.

Как это исправить?

Один из подходов – посредством кода. Класс StudentBodyPresenter может выполнять повторную сортировку данных после их загрузки. Но хотелось бы использовать более гибкое решение, позволяющее применять к данным разные параметры сортировки.

Это можно сделать – причем, полностью в XAML – используя класс CollectionViewSource (Источник представления коллекции) из пространства имен System.Windows.Data. Этот класс используется в сочетании с классом SortDescription (Описание сортировки), описанным в пространстве имен System.ComponentModel. Кроме ссылки и объявления пространства имен XML для библиотеки ElPasoHighSchool, нам понадобится объявление пространства имен XML для System.ComponentModel:

xmlns:componentmodel="clr-namespace:System.ComponentModel;assembly=System.Windows"

Весь CollectionViewSource может описываться в коллекции Resources:

<phone:PhoneApplicationPage.Resources>

<elpaso:StudentBodyPresenter x:Key="studentBodyPresenter" />

<CollectionViewSource x:Key="sortedStudents"

Source="{Binding Source={StaticResource

studentBodyPresenter},

Path=StudentBody.Students}"> <CollectionViewSource.SortDescriptions>

<componentmodel:SortDescription PropertyName="LastName"

Direction="Ascending" /> </CollectionViewSource.SortDescriptions> </CollectionViewSource>

</phone:PhoneApplicationPage.Resources>

Обратите внимание, теперь свойство Source класса CollectionViewSource ссылается на свойство Students свойства StudentBody класса StudentBodyPresenter. Свойство Students типа ObservableCollection<Student>. Свойство Source класса CollectionViewSource должно быть коллекцией.

Объект SortDescription указывает на то, что мы хотим выполнять сортировку по свойству LastName в порядке по возрастанию. Поскольку свойство LastName типа string, никакого дополнительного кода для описания сортировки не требуется.

Теперь можно убрать Binding из DataContext класса Grid, и свойство Source класса ItemsControl может ссылаться на ресурс CollectionViewSource:

<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0"> <ScrollViewer>

<ItemsControl ItemsSource="{Binding Source={StaticResource sortedStudents}}">

</ItemsControl> </ScrollViewer> </Grid>

В результате данные выводятся на экран в алфавитном порядке, что выглядит более привлекательно:

CollectionViewSource может включать несколько объектов SortDescription. Попробуем сделать следующее:

<CollectionViewSource x:Key="sortedStudents"

Source="{Binding Source={StaticResource studentBodyPresenter}, Path=StudentBody.Students}"> <CollectionViewSource.SortDescriptions>

<componentmodel:SortDescription PropertyName="Sex"

Direction="Ascending" /> <componentmodel:SortDescription PropertyName="LastName"

Direction="Ascending" /> </CollectionViewSource.SortDescriptions> </CollectionViewSource>

Теперь сначала выводятся данные всех женщин, а затем всех мужчин.

Или можно выводить имена учащихся мужского пола цветом PowderBlue (Зеленовато- голубой) и имена учащихся женского пола – цветом Pink (Розовый). Это довольно старомодная условность, но все-таки мы имеем дело с данными учащихся, которые посещали школу почти 100 лет назад! В общем, совершенно не важно, какие цвета использовать, но вот как реализовать это?

К счастью, у класса Student есть свойство Sex (Пол), значением которого является текстовая строка, либо «Male» (Мужской), либо «Female» (Женский). Поскольку в DataTemplate мы имеем дело с привязками данных, очевидным решением является применение конвертера данных. В библиотеке Petzold.Phone.Silverlight как раз есть такой конвертер, который идеально подходит для этого случая:

Проект Silverlight: Petzold.Phone.Silverlight Файл: SexToBrushConverter.cs

using System;

using System.Globalization; using System.Windows.Data; using System.Windows.Media;

namespace Petzold.Phone.Silverlight {

public class SexToBrushConverter : IValueConverter {

public Brush MaleBrush { get; set; } public Brush FemaleBrush { get; set; }

public object Convert(object value, Type targetType,

object parameter, CultureInfo culture)

{

string sex = value as string;

switch (sex) {

case "Male": return MaleBrush; case "Female": return FemaleBrush;

}

return null;

}

public object ConvertBack(object value, Type targetType,

object parameter, CultureInfo culture)

{

return null;

}

}

}

Как все конвертеры данных, наш конвертер наследуется от IValueConverter и имеет два метода: Convert и ConvertBack. Этот конвертер также определяет два свойства: MaleBrush (Кисть для Male) и FemaleBrush (Кисть для Female). Эти свойства позволяют нам избежать задания кистей в коде. Здесь реализован только метод Convert: при получении значения «Male» он возвращает MaleBrush и при получении значения «Female» – FemaleBrush.

Теперь сведем все в один проект. Кроме библиотеки ElPasoHighSchool, проект StudentBodyltemsControl также включает ссылку на библиотеку Petzold.Phone.Silverlight. В разделе Resources создаются экземпляры классов StudentBodyPresenter, CollectionViewSource для сортировки и SexToBrushConverter (Конвертер пола в кисть):

Проект Silverlight: StudentBodyItemsControl Файл: MainPage.xaml (фрагмент)

<phone:PhoneApplicationPage.Resources>

<elpaso:StudentBodyPresenter x:Key="studentBodyPresenter" />

<CollectionViewSource x:Key="sortedStudents"

Source="{Binding Source={StaticResource

studentBodyPresenter},

Path=StudentBody.Students}"> <CollectionViewSource.SortDescriptions>

<componentmodel:SortDescription PropertyName="LastName"

Direction="Ascending" /> </CollectionViewSource.SortDescriptions> </CollectionViewSource>

<petzold:SexToBrushConverter x:Key="sexToBrushConverter"

FemaleBrush="Pink" MaleBrush="PowderBlue" /> </phone:PhoneApplicationPage.Resources>

В приведенной ниже разметке я использовал пять элементов TextBlock для отображения полного имени учащегося – LastName, FirstName и MiddleName с запятой и пробелом – и по крайней мере четырем из них необходимы привязки, связывающие свойство Foreground со свойством Sex объекта Student, в которых используется SexToBrushConverter. Одну и ту же привязку необходимо применить четыре раза.

Или, вероятно, мы можем немного упростить разметку, заключив все пять элементов TextBlock в ContentControl. Если свойство Foreground класса ContentControl задается одной привязкой, это же свойство наследуется всеми TextBlock. Это и реализуется в следующем DataTemplate, который во всем остальном полностью повторяет предыдущий DataTemplate.

Проект Silverlight: StudentBodyItemsControl Файл: MainPage.xaml (фрагмент)

<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0"> <ScrollViewer>

<ItemsControl ItemsSource="{Binding

Source={StaticResource sortedStudents}}"> <ItemsControl.ItemTemplate> <DataTemplate>

<Border BorderBrush="{StaticResource PhoneAccentBrush}" BorderThickness="1" CornerRadius="12" Margin="2"> <Grid>

<Grid.RowDefinitions>

<RowDefinition Height="*" /> <RowDefinition Height="*" /> </Grid.RowDefinitions>

<Grid.ColumnDefinitions>

<ColumnDefinition Width="Auto" /> <ColumnDefinition Width="*" /> </Grid.ColumnDefinitions>

<Image Grid.Row="0" Grid.Column="0" Grid.RowSpan="2" Source="{Binding PhotoFilename}" Height="12 0" Width="90" Margin="6" />

<ContentControl Grid.Row="0" Grid.Column="1" HorizontalAlignment="Left" VerticalAlignment="Center" Foreground="{Binding Sex,

Converter={StaticResource sexToBrushConverter}}">

<StackPanel Orientation="Horizontal">

<TextBlock Text="{Binding LastName}" /> <TextBlock Text=", " />

<TextBlock Text="{Binding FirstName}" /> <TextBlock Text=", " />

<TextBlock Text="{Binding MiddleName}" /> </StackPanel> </ContentControl>

<StackPanel Grid.Row="1" Grid.Column="1" Orientation="Horizontal" VerticalAlignment="Center"> <TextBlock Text="Grade Point Average = " /> <TextBlock Text="{Binding GradePointAverage}" /> </StackPanel> </Grid> </Border> </DataTemplate> </ItemsControl.ItemTemplate> </ItemsControl> </ScrollViewer> </Grid>

Полагаю, эффект от добавления цвета стоит затраченных на его реализацию усилий:

Источник: Чарльз Петзольд, Программируем Windows Phone 7, Microsoft Press, © 2011.

По теме:

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