Сегодня, в данной статье мы научимся заполнять иерархическими данными TreeView в WPF использую MVVM.
Для примера давайте возьмем иерархическую структуру данных Город — Улица — Дом
Содержание
Шаг 1 Создание нового проекта
Создадим новое приложение WPF в Visual Studio 2022 и назовем его «TreeViewMVVMExample»
Шаг 2 Класс InotifyPropertyChanged
- Добавим новый класс и назовем его «ViewModelBase». Этот базовый класс уведомляет клиент, что свойства изменились.
- Добавим в код «PropertyChangedEventHandler»
- В итоге класс должен выглядеть следующим образом:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
using System.ComponentModel; namespace TreeViewMVVMExample { public class ViewModelBase : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; public void OnPropertyChanged(string propname) { if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs(propname)); } } } } |
Шаг 3 Класс House
- Создадим класс Alt+Shift+C и назовем его «House». Это класс необходим для определения структуры для Дома
- Установим поля необходимые для дома. В нашем примере это номер дом(HouseNumber)
- Унаследуем этот класс от ViewModelBase и реализуем уведомление об изменении свойств полей.
- В итоге получаем следующий код:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
public class House:ViewModelBase { private int houseNumber; public int HouseNumber { get { return houseNumber; } set { houseNumber = value; OnPropertyChanged(nameof(HouseNumber)); } } public House(int number) { houseNumber = number; } } |
Шаг 4 Класс Street
- Создадим класс Alt+Shift+C и назовем его Street. Это будет модель отвечающая за структуру Улицы на которой могут находится множество домов.
- Добавим свойство отвечающие за наименование улицы
- Добавим в класс свойство содержащие список с домами
- Класс будет наследником ViewModelBase и в нем будет реализовано уведомление об изменении свойств
- В конструктор передаем название улицы и для теста создадим по 3 тестовых домов.
- Код класса Street
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 |
public class Street:ViewModelBase { private string streetName; private List<House> houses; public string StreetName { get { return streetName; } set { streetName = value; OnPropertyChanged("StreetName"); } } public List<House> Houses { get { return houses; } set { houses = value; OnPropertyChanged("Houses"); } } public Street(string strName) { streetName = strName; houses = new List<House>() { new House(1), new House(5), new House(11), }; } } |
Шаг 5 Класс City
- Создадим класс Alt+Shift+C и назовем его City. Этот класс будет моделировать структуру Города.
- Создадим свойство содержащие наименование города
- Создадим свойство в котором будет хранится список улиц
- В конструкторе заполним все свойства тестовыми данными
- Класс является наследником ViewModelBase
- Код класса City
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
public class City:ViewModelBase { private string cityName; private List<Street> streetList; public string CityName { get { return cityName; } set { cityName = value; OnPropertyChanged("CityName"); } } public List<Street> StreetList { get { return streetList; } set { streetList = value;OnPropertyChanged("StreetList"); } } public City(string name) { cityName = name; streetList = new List<Street>() { new Street("Улица 1"), new Street("Улица 2") }; } } |
Мы завершили создание базовых классов модели нашего примера. Теперь нужно связать их с TreeView для вывода информации в иерархическом порядке.
Шаг 6 ViewModel для привязки данных к datacontext
- Создадим новый класс и назовем его «MainWindowViewModel«. Он является ViewModel для нашего View «MainWindow»
- Код выглядит следующим образом
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
public class MainWindowViewModel:ViewModelBase { private List<City> cityList; public List<City> CityList { get { return cityList; } set { cityList = value; OnPropertyChanged("CityList"); } } public MainWindowViewModel() { cityList = new List<City>() { new City("Город 1"), new City("Город 2"), new City("Город 3"), new City("Город 4"), }; } } |
Шаг 7 Создаем View
- Добавим DataContext с указанием на MainWindowViewModel в файл MainWindow.xaml
1d:DataContext="{d:DesignInstance Type=local:MainWindowViewModel}" - Добавим в конструктор класса MainWindow.cs DataContext = new MainWindowViewModel();
- Код для MainWindow.xaml будет следующим
12345678910111213141516171819202122232425262728<Window x:Class="TreeViewMVVMExample.MainWindow"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:local="clr-namespace:TreeViewMVVMExample" d:DataContext="{d:DesignInstance Type=local:MainWindowViewModel}"mc:Ignorable="d"Title="MainWindow" Height="450" Width="400"><Grid><TreeView HorizontalAlignment="Stretch" Margin="10" VerticalAlignment="Stretch" ItemsSource="{Binding CityList}"><TreeView.ItemTemplate><HierarchicalDataTemplate ItemsSource="{Binding StreetList}"><Label Content="{Binding CityName}"/><HierarchicalDataTemplate.ItemTemplate><HierarchicalDataTemplate ItemsSource="{Binding Houses}"><Label Content="{Binding StreetName}"/><HierarchicalDataTemplate.ItemTemplate><DataTemplate><Label Content="{Binding HouseNumber}"/></DataTemplate></HierarchicalDataTemplate.ItemTemplate></HierarchicalDataTemplate></HierarchicalDataTemplate.ItemTemplate></HierarchicalDataTemplate></TreeView.ItemTemplate></TreeView></Grid></Window>
Мы завершили наш проект. Попробуем запустить код и в итоге должно появиться следующие окно