Главная » WPF » Шаблоны данных используемые в WPF

0

Мы уже видели, что шаблоны  данных позволяют  описать внешний  вид дан ных. В этом разделе  мы будем работать с привязкой к XML, но все изложенное сохраняет  силу для привязки к данным любого типа.

Чтобы понять суть шаблонов данных, вернемся к примеру, на котором мы изу чали привязку.  Вместо того чтобы напрямую  привязываться к атрибуту  Title, привяжемся к элементам:

public class Window1 : Window {

public Window1() {

XmlDocument doc = new XmlDocument();

doc.LoadXml(…);

XmlDataProvider dataSource = new XmlDataProvider();

dataSource.Document = doc; Binding bind = new Binding(); bind.Source = dataSource; bind.XPath = «/Media/Book»; ListBox list = new ListBox();

list.SetBinding(ListBox.ItemsSourceProperty, bind); Title = «XML Binding»;

Content = list;

}

}

Так мы получаем на первый взгляд  пустое списковое  поле, которое на самом деле содержит  три пустых элемента,  в чем легко убедиться,  щелкнув  по списку мышью. Поскольку с объектом XmlElement не ассоциирован шаблон, то система просто вызывает его метод ToString, который возвращает  пустую строку, потому что у элементов  ниже «Book» нет потомков.

Тип DataTemplate чем то напоминает ControlTemplate. Оба пользуются  клас сом FrameworkElementFactory для определения дерева отображения. Но ControlTemplate определяет  это дерево для элемента управления, внутри которо го мы пользуемся привязкой к шаблону для связывания отображаемых свойств со свойствами  элемента. Что касается DataTemplate, то он определяет  дерево отображения для элемента  данных, внутри  которого  мы с помощью привязки к данным  связываем отображаемые свойства  со свойствами  данных.  Кроме  того, DataTemplate автоматически устанавливает контекст данных для дерева отобра жения, а именно шаблонный  элемент данных.

Чтобы построить  свой первый шаблон программно, подготовим простое текс товое поле, в котором будет отображаться название книги. Созданный объект DataTemplate будет ассоциирован с XmlElement как тип данных:

DataTemplate template = new DataTemplate();

template.DataType = typeof(XmlElement);

Далее нужно создать дерево отображения для шаблона:

FrameworkElementFactory textFactory =

new FrameworkElementFactory(typeof(TextBlock));

Со свойством TextTextProperty элемента TextBlock необходимо связать под

ходящее выражение  XPath:

Binding bind = new Binding(); bind.XPath=»@Title»; textFactory.SetBinding(TextBlock.TextProperty, bind);

Отметим, что объявлять источник данных необязательно. Свойству DataContext созданного дерева отображения автоматически присвоена  ссылка на элемент, к ко торому применяется шаблон. Теперь можно ассоциировать с шаблоном фабрику:

template.VisualTree = textFactory;

И последний  шаг – записать в свойство ItemTemplate элемента ListBox ссыл ку на только  что определенный шаблон. Если собрать все вместе, то получится простое приложение для отображения названий  книг:

public Window1() {

XmlDocument doc = new XmlDocument();

doc.LoadXml(…);

DataTemplate template = new DataTemplate(); template.DataType = typeof(XmlElement); Binding bind = new Binding(); bind.XPath=»@Title»;

FrameworkElementFactory textFactory =

new FrameworkElementFactory(typeof(TextBlock)); textFactory.SetBinding(TextBlock.TextProperty, bind); template.VisualTree = textFactory;

XmlDataProvider dataSource = new XmlDataProvider();

dataSource.Document = doc; bind = new Binding(); bind.Source = doc; bind.XPath = «/Media/Book»;

ListBox list = new ListBox(); list.ItemTemplate = template; list.SetBinding(ListBox.ItemsSourceProperty, bind);

Title = «XML Binding»; Content = list;

}

У классов DataTemplate и ControlTemplate очень схожие функции и способы применения. Ссылки  на ресурсы часто используются для привязки свойства ItemTemplate списка к шаблону. Написанный выше код выглядит  гораздо проще в виде разметки:

<Window …

xmlns:sx=’clr namespace:System.Xml;assembly=System.Xml’ Title=’XML Binding’

DataContext=’{DynamicResource dataSource}’

<Window.Resources>

<XmlDataProvider x:Key=’dataSource’>

</XmlDataProvider>

<DataTemplate        x:Key=’template’        DataType=’{x:Type sx:XmlElement}’>

<TextBlock Text=’{Binding XPath=@Title}’ />

</DataTemplate>

</Window.Resources>

<ListBox

ItemsSource= ‘{Binding XPath=/Media/Book }’

ItemTemplate=’{DynamicResource template}’ />

</Window>

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

Выбор шаблона

Обычно шаблон ассоциируется с некоторым  элементом  данных, но часто бы вает необходимо  динамически решить, какой шаблон использовать,  – исходя из значения  какого то свойства  (хотя  в главе 7 мы узнаем о триггерах, которые по могают в этом отношении) или глобального  состояния.  Если нужно заменить шаблон целиком, то можно воспользоваться классом DataTemplateSelector.

В этом классе  имеется  единственный метод SelectTemplate, который  позво ляет  реализовать любую  логику  выбора  нужного  шаблона.  Мы  можем  найти шаблон в дочернем элементе (например, ListBox),  вернуть  какие то «зашитые» в код шаблоны или даже динамически создать шаблон для каждого элемента списка.

Начнем  с создания  класса, производного  от DataTemplateSelector, в котором выполняется выбор одного из нескольких  шаблонов. В данном случае мы просто анализируем свойство LocalName объекта XmlElement и ищем ресурс с этим име нем в контейнере:

public class LocalNameTemplateSelector : DataTemplateSelector {

public override DataTemplate SelectTemplate(object item, DependencyObject container) {

XmlElement data = item as XmlElement;

if (data != null) {

return (FrameworkElement)container).FindResource(data.LocalName)

as DataTemplate;

}

return null;

}

}

На этапе инициализации мы построим три шаблона: коричневые прямоуголь ники для книг, серебристые круги для CD и синие круги для DVD. Поскольку се лектор  шаблонов  анализирует локальное  имя объекта XmlElement, для каждого шаблона следует задать атрибут x:Key:

<DataTemplate x:Key=’Book’ DataType=’{x:Type sx:XmlElement}’>

<StackPanel Orientation=’Horizontal’>

<Rectangle Margin=’2’ Width=’14’ Height=’14’ Fill=’Brown’ />

<TextBlock VerticalAlignment=’Center’ Text=’{Binding XPath=@Title}’ />

</StackPanel>

</DataTemplate>

<DataTemplate x:Key=’CD’ DataType=’{x:Type sx:XmlElement}’>

<StackPanel Orientation=’Horizontal’>

<Ellipse Margin=’2’ Width=’14’ Height=’14’ Fill=’Silver’ />

<TextBlock VerticalAlignment=’Center’ Text=’{Binding XPath=@Title}’ />

</StackPanel>

</DataTemplate>

<DataTemplate x:Key=’DVD’ DataType=’{x:Type sx:XmlElement}’>

<StackPanel Orientation=’Horizontal’>

<Ellipse Margin=’2’ Width=’14’ Height=’14’ Fill=’Blue’ />

<TextBlock VerticalAlignment=’Center’ Text=’{Binding XPath=@Title}’ />

</StackPanel>

</DataTemplate>

Осталось  ассоциировать селектор шаблона со списковым  полем вместо стати ческого шаблона  (при  этом мы выберем  все носители  информации, а не только книги):

<Window …

xmlns:sx=’clr namespace:System.Xml;assembly=System.Xml’ Title=’XML Binding’

DataContext=’{DynamicResource dataSource}’

<Window.Resources>

<XmlDataProvider x:Key=’dataSource’>

</XmlDataProvider>

<DataTemplate x:Key=’Book’ DataType=’{x:Type sx:XmlElement}’>

</DataTemplate>

<DataTemplate x:Key=’CD’ DataType=’{x:Type sx:XmlElement}’>

</DataTemplate>

<DataTemplate x:Key=’DVD’ DataType=’{x:Type sx:XmlElement}’>

</DataTemplate>

</Window.Resources>

<ListBox

ItemsSource= ‘{Binding XPath=/Media/*}’>

<ListBox.ItemTemplateSelector>

<l:LocalNameTemplateSelector

xmlns:l=’clr namespace:EssentialWPF’ />

</ListBox.ItemTemplateSelector>

</ListBox>

</Window>

На рис. 6.12 приведен результат  выполнения этой разметки.

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

По теме:

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