Вяжем узлы по-нашему! (WPF)

Всем привет! На сегодняшнем уроке мы научимся выполнять привязку иерархических данных к нашим элементам управления.

Зачем? — Classes, Subclasses

Иерархический data binding бывает нужен в различных ситуациях, например для отображения структурированных данных (разбитых на более мелкие части, которые в свою очередь тоже разбиваются на подклассы)…

Как? — Templates, blabla

В WPF существует удобный способ — HierarchicalDataTemplate. Этот механизм используется как раз для подобных целей и мы им сегодня воспользуемся.

Где? — THE CORE

HierarchicalDataTemplate может применяться в таких контролах, как TreeView или ListBox. Собственно мы рассмотрим именно на примере первого.

Let’s the coding begin

Все как обычно, начинаем с модели aka Data Layer…

Вот наша модель, которую мы собираемся привязывать:

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; }
    }

Кроме того, понадобится вот такой вот класс-фабрика, создающий фейковые иерархические данные (любые совпадения с реальностью случайны ;)):

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:

<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, описанный выше), он нужен для того, чтобы создать фейковые данные.

<local:ModelFactory x:Key="ModelFactory"/>

После того, как экземпляр создан, мы можем привязать данные к ObjectDataProvider:

<ObjectDataProvider x:Key="ModelProvider" ObjectInstance="{StaticResource ModelFactory}" MethodName="CreateSource"/>

ObjectDataProvider — очень удобная штука, которая позволяет нам не писать ни единой строчки кода в Window1.xaml.cs. Провайдер сам вызовет метод, получающий данные (CreateSource). Провайдер умеет получать данные, но не знает, что с ними делать дальше.

Для отображения данных мы выбрали TreeView контрол. Присваиваем данные в свойство ItemsSource ему вот таким образом:

<TreeView 
            ItemsSource="{Binding Source={StaticResource ModelProvider}}"
            ItemTemplate="{StaticResource theDataTemplate}"/>

Итак, принцип иерархического шаблона таков: шаблон применяется к каждому экземпляру в списке данных (из ItemsSource), если встречаются совпадающие свойства (в секции Binding), то они отображаются, согласно описания.

Например: , свойство Name имеется у классов Country, City, Company, а значит у всех будет отображаться контрол TextBlock иерархически. Это же относится и к остальным свойствам.

Итак, вот что у нас получилось в итоге:

Всем спасибо, ждите интересных уроков по WPF!

Надеюсь вам понравился изложенный материал, так что не стесняемся комментировать и голосовать за него.

Рейтинг
( Пока оценок нет )
Загрузка ...