Главная » C#, Windows Runtime, XAML, Разработка для Windows 8 » Привязка к коллекции Windows Runtime

0

При привязке простых свойств обычно не возникает проблем. Но вот привязка коллекций требует дополнительных усилий.

Расширим класс Employee, перегрузив метод ToString:

public override string ToString()

{

return String.Format("{0} {1}", firstName, lastName);

}

Этот метод нам понадобится при заполнении одного из элементов управления коллекцией элементов типа Employee.

Хочу сразу отметить, что коллекции способны принимать только те элементы, которые являются наследниками ItemsControl. Среди таких  элементов  можно выделить и ListBox, который способен отображать список элементов.

Прежде   чем   писать   код,   давайте определимся  со   свойствами,   которые используются при привязке коллекции к элементу. Тут существуют три свойства:

·                   ItemsSource    —задает     коллекцию     элементов.     Если     не     задан DisplayMemberPath,  то  каждый  элемент  попытается   вызвать метод ToString. Вот почему мы и предопределили ToString;

·                   ItemTemplate   —   используется  для   задания   шаблона   отображения конкретного элемента;

·                   DisplayMemberPath — задает конкретное свойство для  отображения в элементе управления.

А вот теперь перейдем к коду. Сначала расширим наш интерфейс,  отобразив

ListBox:

<Page x:Class="Chapter5_Binding.MainPage" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:data="using:Chapter5_Binding">

<StackPanel>

<ListBox Height="300" Name="lstEmp"></ListBox>

<Grid x:Name="LayoutRoot" Background="White" Width="400" DataContext="{Binding SelectedItem, ElementName=lstEmp}">

<Grid.RowDefinitions>

<RowDefinition Height="Auto"></RowDefinition>

<RowDefinition Height="Auto"></RowDefinition>

<RowDefinition Height="Auto"></RowDefinition>

<RowDefinition Height="Auto"></RowDefinition>

</Grid.RowDefinitions>

<Grid.ColumnDefinitions>

<ColumnDefinition></ColumnDefinition>

<ColumnDefinition></ColumnDefinition>

</Grid.ColumnDefinitions>

<TextBlock Text="First Name:" Grid.Row="0" Grid.Column="0">

</TextBlock>

<TextBox Text="{Binding Path=FirstName}"  Grid.Row="0" Grid.Column="1">

</TextBox>

<TextBlock Text="Last Name:" Grid.Row="1" Grid.Column="0">

</TextBlock>

<TextBox Text="{Binding Path=LastName}"  Grid.Row="1" Grid.Column="1">

</TextBox>

<TextBlock Text="EMail:" Grid.Row="2" Grid.Column="0">

</TextBlock>

<TextBox Text="{Binding Path=EMail}"  Grid.Row="2" Grid.Column="1">

</TextBox>

<TextBlock Text="Age:" Grid.Row="3" Grid.Column="0">

</TextBlock>

<TextBox Text="{Binding Path=Age}"  Grid.Row="3" Grid.Column="1">

</TextBox>

</Grid>

</StackPanel>

</Page>

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

Теперь  реализуем код,  создающий список  элементов.  В  качестве  структуры данных  можно  выбрать любой  класс  —  главное, чтобы  он  реализовывал интерфейс IEnumerable.

protected override void OnNavigatedTo(NavigationEventArgs e)

{

List<Employee> employeeList = new List<Employee>();

Employee emp = new Employee(); emp.FirstName = "Sergiy"; emp.LastName = "Baydachnyy"; emp.EMail = "sbaidachni@gmail.com"; emp.Age = 31;

employeeList.Add(emp); emp = new Employee();

emp.FirstName = "Sergii";

emp.LastName = "Lutai";

emp.EMail = "sergii.lutai@dct.ua"; emp.Age = 27;

employeeList.Add(emp);

lstEmp.ItemsSource = employeeList;

}

Как видите, мы создали два элемента и выполнили привязку к элементу ListBox,

получив полностью рабочий пример!

Результат работы приложения можно увидеть на рисунке ниже:

Рис. 5.1.

Однако если Вы попробуете изменить конкретный элемент через его детальную форму, то сможете увидеть, что введенные изменения сохраняются, но ListBox упорно не хочет их отображать. Это все от того, что ListBox реагирует лишь на изменение значений только тех свойств, с которыми он связан явно. То есть, если мы меняем свойство LastName, то инициируется событие OnPropertyChange, но ListBox  никакого дела до него нет, так как он использует метод ToString и  не  связан с  конкретным  свойством  (или  свойствами).   Чтобы  исправить ситуацию, можно воспользоваться  методом  DisplayMemberPath, указав имя свойства явно. Все дело в  том, что мы  хотим отобразить комбинацию имени и фамилии, а такого свойства у нас нет. Определять же новое свойство было бы  глупо.  Поэтому  мы   воспользуемся возможностью ListBox  определить шаблон выдаваемых элементов, заполнив  свойство ItemTemplate. Вот как будет выглядеть элемент ListBox:

<ListBox Height="300" Width="400" Name="lstEmp">

<ListBox.ItemTemplate>

<DataTemplate>

<Border Background="Gray" BorderThickness="2" CornerRadius="10" Width="396" Height="30">

<StackPanel Orientation="Horizontal" Margin="5">

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

<TextBlock Text=" "></TextBlock>

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

</StackPanel>

</Border>

</DataTemplate>

</ListBox.ItemTemplate>

</ListBox>

Тут мы не только решили проблему с отображением измененных  данных, но и изменили внешний вид элемента в списке на более симпатичный.

В   завершение раздела  следует  отметить,  что  вместо класса   List   лучше использовать коллекцию ObservableCollection. Дело в том, что если Вы решите добавлять или удалять элементы из списка, то  столкнетесь с необходимостью реализации интерфейса INotifyCollectionChanged. А ObservableCollection уже реализует этот интерфейс.

Сергей Лутай, Сергей Байдачный, Windows 8 для C# разработчиков

По теме:

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