Всем привет! На сегодняшнем уроке мы научимся выполнять привязку иерархических данных к нашим элементам управления.
Зачем? — Classes, Subclasses
Иерархический data binding бывает нужен в различных ситуациях, например для отображения структурированных данных (разбитых на более мелкие части, которые в свою очередь тоже разбиваются на подклассы)…
Как? — Templates, blabla
В WPF существует удобный способ — HierarchicalDataTemplate. Этот механизм используется как раз для подобных целей и мы им сегодня воспользуемся.
Где? — THE CORE
HierarchicalDataTemplate может применяться в таких контролах, как TreeView или ListBox. Собственно мы рассмотрим именно на примере первого.
Let’s the coding begin
Все как обычно, начинаем с модели aka Data Layer…
Вот наша модель, которую мы собираемся привязывать:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
public class Country { public string Name { get; set; } public List<City> Cities { get; set; } } public class City { public string Name { get; set; } public List<Company> Companies { get; set; } } public class Company { public string Name { get; set; } public string Address { get; set; } public List<Employee> Employees { get; set; } } public class Employee { public string FirstName { get; set; } public string LastName { get; set; } public string Title { get; set; } public int Age { get; set; } } |
Кроме того, понадобится вот такой вот класс-фабрика, создающий фейковые иерархические данные (любые совпадения с реальностью случайны ;)):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 |
public class ModelFactory { public List<Country> CreateSource() { return new List<Country> { new Country { Name = "Russia", Cities = new List<City> { #region City: MOSCOW new City { Name = "Moscow", Companies = new List<Company> { #region MOSCOW, Company 1 new Company { Name = "Y Trade Ltd.", Address = "Lenina St. 1", Employees = new List<Employee> { new Employee { Age = 30, FirstName = "Ivan", LastName = "Petrov", Title = "President" }, new Employee { Age = 28, FirstName = "Nikolay", LastName = "Vasilev", Title = "Project Manager" }, new Employee { Age = 27, FirstName = "Ilya", LastName = "Ileev", Title = "Architector" }, new Employee { Age = 42, FirstName = "Andrey", LastName = "Goncharov", Title = "Senior Java Developer" }, new Employee { Age = 22, FirstName = "Nikita", LastName = "Nikolaev", Title = "Senior .NET Developer" }, } }, #endregion #region MOSCOW, Company 2 new Company { Name = "Z-SOFT", Address = "Vrubelya 1", Employees = new List<Employee> { new Employee { Age = 45, FirstName = "Marina", LastName = "Svetikova", Title = "Director" }, new Employee { Age = 38, FirstName = "Nikolay", LastName = "Andreev", Title = "HR" }, new Employee { Age = 29, FirstName = "Sergey", LastName = "Sergeev", Title = ".NET Developer" }, new Employee { Age = 31, FirstName = "Svetlana", LastName = "Marinina", Title = "Junior .NET Developer" } } } #endregion } }, #endregion #region City: Omsk new City { Name = "Omsk", Companies = new List<Company> { #region OMSK, Company 1 new Company { Name = "IT-ProSoft Trading Consulting Ltd.", Employees = new List<Employee> { new Employee { Age = 27, FirstName = "Andrey", LastName = "Petrov", Title = "President" }, new Employee { Age = 35, FirstName = "Mikhail", LastName = "Danilov", Title = "HR" }, new Employee { Age = 29, FirstName = "Igor", LastName = "Samoilenko", Title = ".NET Trainer" }, new Employee { Age = 25, FirstName = "Alexander", LastName = "Sidorov", Title = ".NET Developer" } } } #endregion } } #endregion } } }; } } |
Итак, модель у нас создается, самое время написать слой привязки модели к GUI, воспользуемся ObjectDataProvider и инстанцией класса ModelFactory. Вы увидите, что это очень легко осуществимо, благодаря XAML разметке:
Вот наш Window1.xaml:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
<Window x:Class="WpfApplication1.Window1" xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:WpfApplication1" Title="Window1" Height="300" Width="300"> <Window.Resources> <local:ModelFactory x:Key="ModelFactory"/> <ObjectDataProvider x:Key="ModelProvider" ObjectInstance="{StaticResource ModelFactory}" MethodName="CreateSource"/> <HierarchicalDataTemplate x:Key="theDataTemplate" ItemsSource="{Binding Path=Items}"> <TextBlock Text="{Binding Path=Name}"> <StackPanel Orientation="Horizontal"> <TextBlock Text="{Binding FirstName}"/> <TextBlock Text="{Binding LastName}" Margin="5,0,0,0"/> <TextBlock Text="{Binding Title}" Margin="5,0,0,0"/> <TextBlock Text="{Binding Age}" Margin="5,0,0,0"/> </StackPanel> </TextBlock> </HierarchicalDataTemplate> </Window.Resources> <Grid DataContext="{StaticResource ModelProvider}"> <TreeView ItemsSource="{Binding Source={StaticResource ModelProvider}}" ItemTemplate="{StaticResource theDataTemplate}"/> </Grid> </Window> |
Код требует некоторого объяснения.
Сначала мы создаем экземпляр нашей модели (класс ModelFactory, описанный выше), он нужен для того, чтобы создать фейковые данные.
1 |
<local:ModelFactory x:Key="ModelFactory"/> |
После того, как экземпляр создан, мы можем привязать данные к ObjectDataProvider:
1 |
<ObjectDataProvider x:Key="ModelProvider" ObjectInstance="{StaticResource ModelFactory}" MethodName="CreateSource"/> |
ObjectDataProvider — очень удобная штука, которая позволяет нам не писать ни единой строчки кода в Window1.xaml.cs. Провайдер сам вызовет метод, получающий данные (CreateSource). Провайдер умеет получать данные, но не знает, что с ними делать дальше.
Для отображения данных мы выбрали TreeView контрол. Присваиваем данные в свойство ItemsSource ему вот таким образом:
1 2 3 |
<TreeView ItemsSource="{Binding Source={StaticResource ModelProvider}}" ItemTemplate="{StaticResource theDataTemplate}"/> |
Итак, принцип иерархического шаблона таков: шаблон применяется к каждому экземпляру в списке данных (из ItemsSource), если встречаются совпадающие свойства (в секции Binding), то они отображаются, согласно описания.
Например: , свойство Name имеется у классов Country, City, Company, а значит у всех будет отображаться контрол TextBlock иерархически. Это же относится и к остальным свойствам.
Итак, вот что у нас получилось в итоге:
Всем спасибо, ждите интересных уроков по WPF!
Надеюсь вам понравился изложенный материал, так что не стесняемся комментировать и голосовать за него.
Похожие записи: