xamlwinui-3winuiwindows-app-sdk

How to populate treeview in WinUI 3?


I have one model named Visit

public class Visit
{
    public int {get; set;}
    public DateTime Date {get; set;}
    public string VisitNo {get; set;}
    public string Details {get;set;}
}

How can I populate a TreeView WinUI 3 like main roots are Years and Childrens are VisitNos.

I expecting the result below.

+2022
  -0001
  -0002
+2023
  -0003
  -0004
  -0005

Solution

  • I guess this will do:

    using CommunityToolkit.Mvvm.ComponentModel;
    using Microsoft.UI.Xaml;
    using Microsoft.UI.Xaml.Controls;
    using System;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.Linq;
    
    namespace TreeViewExample;
    
    public class Visit
    {
        public int Id { get; set; }
        public DateTime Date { get; set; }
        public string VisitNo { get; set; } = string.Empty;
        public string Details { get; set; } = string.Empty;
    }
    
    public partial class YearItem : ObservableObject
    {
        public YearItem(int year)
        {
            Year = year;
        }
    
        [ObservableProperty]
        private int year;
    
        [ObservableProperty]
        private ObservableCollection<Visit> visits = new();
    }
    
    public class TreeViewTemplateSelector : DataTemplateSelector
    {
        public DataTemplate? YearTemplate { get; set; }
    
        public DataTemplate? VisitTemplate { get; set; }
    
        protected override DataTemplate? SelectTemplateCore(object item)
        {
            return item switch
            {
                YearItem => YearTemplate,
                Visit => VisitTemplate,
                _ => throw new NotSupportedException(),
            };
        }
    }
    
    public partial class MainPageViewModel : ObservableObject
    {
        [ObservableProperty]
        private ObservableCollection<YearItem> yearItems = new();
    
        public MainPageViewModel()
        {
            List<Visit> visits = new()
            {
                new Visit { Id = 1, Date = DateTime.Now.AddYears(-1).AddMonths(-3), VisitNo = "001", Details = "Visit 1" },
                new Visit { Id = 2, Date = DateTime.Now.AddYears(-1), VisitNo = "002", Details = "Visit 2" },
                new Visit { Id = 3, Date = DateTime.Now.AddMonths(-2), VisitNo = "003", Details = "Visit 3" },
                new Visit { Id = 4, Date = DateTime.Now.AddMonths(-1), VisitNo = "004", Details = "Visit 4" },
                new Visit { Id = 5, Date = DateTime.Now, VisitNo = "005", Details = "Visit 5" }
            };
    
            foreach (Visit visit in visits)
            {
                if (YearItems
                    .Where(x => x.Year == visit.Date.Year)
                    .FirstOrDefault() is not YearItem visitsViewModel)
                {
                    visitsViewModel = new(visit.Date.Year);
                    YearItems.Add(visitsViewModel);
                }
    
                visitsViewModel.Visits.Add(visit);
            }
        }
    }
    
    <Page
        x:Class="TreeViewExample.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:local="using:TreeViewExample"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"
        mc:Ignorable="d">
        <Page.DataContext>
            <local:MainPageViewModel x:Name="ViewModel" />
        </Page.DataContext>
    
        <Page.Resources>
            <local:TreeViewTemplateSelector x:Key="TreeViewTemplateSelector">
                <local:TreeViewTemplateSelector.YearTemplate>
                    <DataTemplate x:DataType="local:YearItem">
                        <TreeViewItem
                            Content="{x:Bind Year}"
                            ItemsSource="{x:Bind Visits}" />
                    </DataTemplate>
                </local:TreeViewTemplateSelector.YearTemplate>
                <local:TreeViewTemplateSelector.VisitTemplate>
                    <DataTemplate x:DataType="local:Visit">
                        <TextBlock Text="{x:Bind VisitNo}" />
                    </DataTemplate>
                </local:TreeViewTemplateSelector.VisitTemplate>
            </local:TreeViewTemplateSelector>
        </Page.Resources>
    
        <Grid>
            <TreeView
                ItemTemplateSelector="{StaticResource TreeViewTemplateSelector}"
                ItemsSource="{x:Bind ViewModel.YearItems, Mode=OneWay}" />
        </Grid>
    </Page>