Getting Started with .NET MAUI TreeView

19 Sep 202424 minutes to read

This section guides you through setting up and configuring a TreeView in your .NET MAUI application. Follow the steps below to add a basic TreeView to your project.

Prerequisites

Before proceeding, ensure the following are in place:

  1. Install .NET 7 SDK or later.
  2. Set up a .NET MAUI environment with Visual Studio 2022 (v17.3 or later) or VS Code. For VS Code users, ensure that the .NET MAUI workload is installed and configured as described here.

Step 1: Create a .NET MAUI project

Visual Studio

  1. Go to File > New > Project and choose the .NET MAUI App template.
  2. Name the project and choose a location. Then, click Next.
  3. Select the .NET framework version. Then, click Create.

Visual Studio Code

  1. Open the command palette by pressing Ctrl+Shift+P and type .NET:New Project and Enter.
  2. Choose the .NET MAUI App template.
  3. Select the project location, type the project name and press Enter.
  4. Then choose Create Project.

Step 2: Install the Syncfusion MAUI TreeView NuGet Package

  1. In Solution Explorer, right-click the project and choose Manage NuGet Packages.
  2. Search for Syncfusion.Maui.TreeView and install the latest version.
  3. Ensure the necessary dependencies are installed correctly, and the project is restored.

Step 3: Register the handler

The Syncfusion.Maui.Core is a dependent package for all the Syncfusion controls of .NET MAUI. In the MauiProgram.cs file, register the handler for Syncfusion core.

using Microsoft.Maui.Controls.Hosting;
using Microsoft.Maui.Controls.Xaml;
using Microsoft.Maui.Hosting;
using Syncfusion.Maui.Core.Hosting;

namespace GettingStarted
{
    public class MauiProgram 
    {
        public static MauiApp CreateMauiApp()
        {
            var builder = MauiApp.CreateBuilder();
            builder
                .UseMauiApp<App>()
                .ConfigureFonts(fonts =>
                {
                    fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
                });

            builder.ConfigureSyncfusionCore();
            return builder.Build();
        }
    }
}

Step 4: Add a Basic TreeView

  1. To initialize the control, import the Syncfusion.Maui.TreeView namespace into your code.
  2. Initialize SfTreeView.
<ContentPage   
    . . .
    xmlns:syncfusion="clr-namespace:Syncfusion.Maui.TreeView;assembly=Syncfusion.Maui.TreeView">

    <syncfusion:SfTreeView />
</ContentPage>
using Syncfusion.Maui.TreeView;
. . .

public partial class MainPage : ContentPage
{
    public MainPage()
    {
        InitializeComponent();
        SfTreeView treeView = new SfTreeView();
        this.Content = treeView;
    }
}

Step 5: Data population

TreeView can be populated either with the data source by using a ItemsSource or by creating & adding the TreeViewNode to Nodes property.

Populating Nodes without data source - Unbound Mode

You can create and manage the TreeViewNode objects by yourself to display the data in a hierarchical view. To create a tree view, you can use a TreeView control and a hierarchy of TreeViewNode objects. You can create the node hierarchy by adding one or more root nodes to the TreeView control’s Nodes collection. Each TreeViewNode can then have more nodes added to its Children collection. You can nest the tree view nodes to any depth you need.

IMPORTANT

ItemsSource is an alternative mechanism to Nodes for adding content into the TreeView control. You cannot set both ItemsSource and Nodes at the same time. When you use ItemsSource, nodes are created internally, but you cannot access them from the Nodes property.

<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:syncfusion="clr-namespace:Syncfusion.Maui.TreeView;assembly=Syncfusion.Maui.TreeView"
             xmlns:treeviewengine="clr-namespace:Syncfusion.TreeView.Engine;assembly=Syncfusion.Maui.TreeView"
             x:Class="GettingStarted.MainPage">
    <ContentPage.Content>
       <syncfusion:SfTreeView x:Name="treeView">
            <syncfusion:SfTreeView.Nodes>
                <treeviewengine:TreeViewNode Content="Australia">
                    <treeviewengine:TreeViewNode.ChildNodes>
                        <treeviewengine:TreeViewNode Content="New South Wales">
                            <treeviewengine:TreeViewNode.ChildNodes>
                                <treeviewengine:TreeViewNode Content="Sydney"/>
                            </treeviewengine:TreeViewNode.ChildNodes>
                        </treeviewengine:TreeViewNode>
                    </treeviewengine:TreeViewNode.ChildNodes>
                </treeviewengine:TreeViewNode>
                <treeviewengine:TreeViewNode Content="United States of America">
                    <treeviewengine:TreeViewNode.ChildNodes>
                        <treeviewengine:TreeViewNode Content="New York"/>
                        <treeviewengine:TreeViewNode Content="California">
                            <treeviewengine:TreeViewNode.ChildNodes>
                                <treeviewengine:TreeViewNode Content="San Francisco"/>
                            </treeviewengine:TreeViewNode.ChildNodes>
                        </treeviewengine:TreeViewNode>
                    </treeviewengine:TreeViewNode.ChildNodes>
                </treeviewengine:TreeViewNode>
            </syncfusion:SfTreeView.Nodes>
        </syncfusion:SfTreeView>
    </ContentPage.Content>
</ContentPage>
using Microsoft.Maui.Controls;
using Syncfusion.Maui.TreeView;
using Syncfusion.TreeView.Engine;
using System;

namespace GettingStarted
{
    public class MainPage : ContentPage
    {
        public MainPage()
        {
            InitializeComponent();
            SfTreeView treeView = new SfTreeView();

            var australia = new TreeViewNode() { Content = "Australia" };
            var nsw = new TreeViewNode() { Content = "New South Wales" };
            var sydney = new TreeViewNode() { Content = "Sydney" };
            australia.ChildNodes.Add(nsw);
            nsw.ChildNodes.Add(sydney);
 
            var usa = new TreeViewNode() { Content = "United States of America" };
            var newYork = new TreeViewNode() { Content = "New York," };
            var california = new TreeViewNode() { Content = "California" };
            var sanFrancisco = new TreeViewNode() { Content = "San Francisco" };
            usa.ChildNodes.Add(newYork);
            usa.ChildNodes.Add(california);
            California.ChildNodes.Add(sanFrancisco);
            treeView.Nodes.Add(australia);
            treeView.Nodes.Add(usa);

            this.Content = treeView;
        }
    }
}

Step 6: Running the Application

Press F5 to build and run the application. Once compiled, the TreeView will be displayed with the data provided.

Here is the result of the previous codes,

Download the entire source code from GitHub here.

.NET MAUI TreeView getting started UnBoundMode

Populating nodes by data binding - Bound mode

Define the Model

Create a simple data model as shown in the following code example, and save it as FileManager.cs file:

public class FileManager : INotifyPropertyChanged
{
   private string itemName;
   private ImageSource imageIcon;
   private ObservableCollection<FileManager> subFiles;

   public ObservableCollection<FileManager> SubFiles
   {
      get { return subFiles; }
      set
      {
         subFiles = value;
         RaisedOnPropertyChanged("SubFiles");
      }
   }

   public string ItemName
   {
      get { return itemName; }
      set
      {
         itemName = value;
         RaisedOnPropertyChanged("ItemName");
      }
   }
 
   public ImageSource ImageIcon
   {
       get { return imageIcon; }
       set
       {
          imageIcon = value;
          RaisedOnPropertyChanged("ImageIcon");
       }
   }

   public event PropertyChangedEventHandler PropertyChanged;

   public void RaisedOnPropertyChanged(string propertyName)
   {
      if (PropertyChanged != null)
      {
         PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
      }
   }
}

NOTE

If you want your data model to respond to property changes, then implement INotifyPropertyChanged interface in your model class.

Define the View Model

Create a model repository class with ImageNodeInfo collection property initialized with required number of data objects in a new class file as shown in the following code example, and save it as FileManagerViewModel.cs file:

public class FileManagerViewModel
{
   private ObservableCollection<FileManager> imageNodeInfo;

   public FileManagerViewModel()
   {
      GenerateSource();
   }

   public ObservableCollection<FileManager> ImageNodeInfo
   {
      get { return imageNodeInfo; }
      set { this.imageNodeInfo = value; }
   }

   private void GenerateSource()
   {
      var nodeImageInfo = new ObservableCollection<FileManager>();
      var doc = new FileManager() { ItemName = "Documents", ImageIcon = "folder.png" };
      var download = new FileManager() { ItemName = "Downloads", ImageIcon = "folder.png" };
      var mp3 = new FileManager() { ItemName = "Music", ImageIcon ="folder.png" };
      var pictures = new FileManager() { ItemName = "Pictures", ImageIcon = "folder.png" };
      var video = new FileManager() { ItemName = "Videos", ImageIcon ="folder.png" };

      var pollution = new FileManager() { ItemName = "Environmental Pollution.docx", ImageIcon = "word.png" };
      var globalWarming = new FileManager() { ItemName = "Global Warming.ppt", ImageIcon = "ppt.png" };
      var sanitation = new FileManager() { ItemName = "Sanitation.docx", ImageIcon = "word.png"};
      var socialNetwork = new FileManager() { ItemName = "Social Network.pdf", ImageIcon ="pdfimage.png" };
      var youthEmpower = new FileManager() { ItemName = "Youth Empowerment.pdf", ImageIcon = "pdfimage.png" };
          
      var tutorials = new FileManager() { ItemName = "Tutorials.zip", ImageIcon = "zip.png" };
      var typeScript = new FileManager() { ItemName = "TypeScript.7z", ImageIcon ="zip.png" };
      var uiGuide = new FileManager() { ItemName = "UI-Guide.pdf", ImageIcon = "pdfimage.png"};

      var song = new FileManager() { ItemName = "Gouttes", ImageIcon = "audio.png" };

      var camera = new FileManager() { ItemName = "Camera Roll", ImageIcon = "folder.png" };
      var stone = new FileManager() { ItemName = "Stone.jpg", ImageIcon = "image.png" };
      var wind = new FileManager() { ItemName = "Wind.jpg", ImageIcon = "image.png"};

      var img0 = new FileManager() { ItemName = "WIN_20160726_094117.JPG", ImageIcon = "people_circle23.png" };
      var img1 = new FileManager() { ItemName = "WIN_20160726_094118.JPG", ImageIcon = "people_circle2.png" };

      var video1 = new FileManager() { ItemName = "Naturals.mp4", ImageIcon = "video.png" };
      var video2 = new FileManager() { ItemName = "Wild.mpeg", ImageIcon = "video.png" };

      doc.SubFiles = new ObservableCollection<FileManager>
      {
         pollution,
         globalWarming,
         sanitation,
         socialNetwork,
         youthEmpower
      };

      download.SubFiles = new ObservableCollection<FileManager>
      {
         tutorials,
         TypeScript,
         uiGuide
      };

      mp3.SubFiles = new ObservableCollection<FileManager>
      {
         song
      };

      pictures.SubFiles = new ObservableCollection<FileManager>
      {
         camera,
         stone,
         wind
      };
      
      camera.SubFiles = new ObservableCollection<FileManager>
      {
         img0,
         img1
      };

      video.SubFiles = new ObservableCollection<FileManager>
      {
         video1,
         video2
      };

      nodeImageInfo.Add(doc);
      nodeImageInfo.Add(download);
      nodeImageInfo.Add(mp3);
      nodeImageInfo.Add(pictures);
      nodeImageInfo.Add(video);
      imageNodeInfo = nodeImageInfo;
  }
}

Bind the data source

Create a ViewModel instance and set it as the ListView’s BindingContext. This enables property binding from ViewModel class.

To populate the TreeView by binding the ItemsSource to a hierarchical data source. To create a tree view using data binding, set a hierarchical collection to the ItemsSource property. Then in the ItemTemplate and ExpanderTemplate, set the child items collection to the ItemsSource property.

IMPORTANT

ItemsSource is an alternative mechanism to Nodes for adding content into the TreeView control. You cannot set both ItemsSource and Nodes at the same time. When you use ItemsSource, nodes are created internally, but you cannot access them from the Nodes property.

<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:syncfusion="clr-namespace:Syncfusion.Maui.TreeView;assembly=Syncfusion.Maui.TreeView"
             xmlns:local="clr-namespace:GettingStarted;assembly=GettingStarted"
             x:Class="GettingStarted.MainPage">

  <ContentPage.BindingContext>
    <local:FileManagerViewModel x:Name="viewModel" />
  </ContentPage.BindingContext>
   <syncfusion:SfTreeView x:Name="treeView" 
                   ItemsSource="{Binding ImageNodeInfo}" 
                   ChildPropertyName="SubFiles"/>
</ContentPage>
using Syncfusion.Maui.TreeView;

namespace GettingStarted;

public partial class MainPage : ContentPage
{
    public MainPage()
    {
        InitializeComponent();
        SfTreeView treeView = new SfTreeView();
        FileManagerViewModel viewModel = new FileManagerViewModel();
        treeView.ItemsSource = viewModel.ImageNodeInfo; 
        treeView.ChildPropertyName = "SubFiles";
        this.Content = treeView;
    }
}

Creating hierarchical Data Model for tree view

Create an hierarchical data model to bind it to the control.

Create a simple hierarchical data source as shown in the following code example in a new class file, and save it as FileManager.cs file.

public class Folder : INotifyPropertyChanged
{
    private string itemName;
    private ImageSource imageIcon;
    private ObservableCollection<File> files;

    public Folder()
    {
    }

    public ObservableCollection<File> Files
    {
        get { return files; }
        set
        {
            files = value;
            RaisedOnPropertyChanged("Files");
        }
    }

    public string ItemName
    {
        get { return itemName; }
        set
        {
            itemName = value;
            RaisedOnPropertyChanged("ItemName");
        }
    }

    public ImageSource ImageIcon
    {
        get { return imageIcon; }
        set
        {
            imageIcon = value;
            RaisedOnPropertyChanged("ImageIcon");
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    public void RaisedOnPropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

public class File : INotifyPropertyChanged
{
    private string itemName;
    private ImageSource imageIcon;
    private ObservableCollection<SubFile> subFiles;

    public File()
    {
    }

    public ObservableCollection<SubFile> SubFiles
    {
        get { return subFiles; }
        set
        {
            subFiles = value;
            RaisedOnPropertyChanged("SubFiles");
        }
    }

    public string ItemName
    {
        get { return itemName; }
        set
        {
            itemName = value;
            RaisedOnPropertyChanged("ItemName");
        }
    }

    public ImageSource ImageIcon
    {
        get { return imageIcon; }
        set
        {
            imageIcon = value;
            RaisedOnPropertyChanged("ImageIcon");
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    public void RaisedOnPropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

public class SubFile : INotifyPropertyChanged
{
    private string itemName;
    private ImageSource imageIcon;

    public SubFile()
    {
    }

    public string ItemName
    {
        get { return itemName; }
        set
        {
            itemName = value;
            RaisedOnPropertyChanged("ItemName");
        }
    }

    public ImageSource ImageIcon
    {
        get { return imageIcon; }
        set
        {
            imageIcon = value;
            RaisedOnPropertyChanged("ImageIcon");
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    public void RaisedOnPropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

NOTE

If you need your hierarchical data model to respond to the property changes, then implement the INotifyPropertyChanged interface in your model class.

Create a model repository class with the Folders collection property initialized with the required number of data objects in a new class file as shown in the following code example, and save it as FileManagerViewModel.cs file:

public class FileManagerViewModel
{
    public ObservableCollection<Folder> Folders { get; set; }

    public FileManagerViewModel()
    {
        this.Folders = GetFiles();
    }

    private ObservableCollection<Folder> GetFiles()
    {
        var nodeImageInfo = new ObservableCollection<Folder>();

        var doc = new Folder() { ItemName = "Documents", ImageIcon = "folder.png" };
        var download = new Folder() { ItemName = "Downloads", ImageIcon = "folder.png" };
        var mp3 = new Folder() { ItemName = "Music", ImageIcon ="folder.png" };
        var pictures = new Folder() { ItemName = "Pictures", ImageIcon = "folder.png" };
        var video = new Folder() { ItemName = "Videos", ImageIcon ="folder.png" };

        var pollution = new File() { ItemName = "Environmental Pollution.docx", ImageIcon = "word.png" };
        var globalWarming = new File() { ItemName = "Global Warming.ppt", ImageIcon = "ppt.png" };
        var sanitation = new File() { ItemName = "Sanitation.docx", ImageIcon = "word.png"};
        var socialNetwork = new File() { ItemName = "Social Network.pdf", ImageIcon ="pdfimage.png" };
        var youthEmpower = new File() { ItemName = "Youth Empowerment.pdf", ImageIcon = "pdfimage.png" };

        var tutorials = new File() { ItemName = "Tutorials.zip", ImageIcon = "zip.png" };
        var typeScript = new File() { ItemName = "TypeScript.7z", ImageIcon ="zip.png" };
        var uiGuide = new File() { ItemName = "UI-Guide.pdf", ImageIcon = "pdfimage.png"};

        var song = new File() { ItemName = "Gouttes", ImageIcon = "audio.png" };

        var camera = new File() { ItemName = "Camera Roll", ImageIcon = "folder.png" };
        var stone = new File() { ItemName = "Stone.jpg", ImageIcon = "image.png" };
        var wind = new File() { ItemName = "Wind.jpg", ImageIcon = "image.png"};

        var img0 = new SubFile() { ItemName = "WIN_20160726_094117.JPG", ImageIcon = "people_circle23.png" };
        var img1 = new SubFile() { ItemName = "WIN_20160726_094118.JPG", ImageIcon = "people_circle2.png" };

        var video1 = new File() { ItemName = "Naturals.mp4", ImageIcon = "video.png" };
        var video2 = new File() { ItemName = "Wild.mpeg", ImageIcon = "video.png" };

        doc.Files = new ObservableCollection<File>
        {
            pollution,
            globalWarming,
            sanitation,
            socialNetwork,
            youthEmpower
        };

        download.Files = new ObservableCollection<File>
        {
            games,
            tutorials,
            typeScript,
            uiGuide
        };

        mp3.Files = new ObservableCollection<File>
        {
            song
        };

        pictures.Files = new ObservableCollection<File>
        {
            camera,
            stone,
            wind
        };

        camera.SubFiles = new ObservableCollection<SubFile>
        {
            img0,
            img1
        };

        video.Files = new ObservableCollection<File>
        {
            video1,
            video2
        };

        nodeImageInfo.Add(doc);
        nodeImageInfo.Add(download);
        nodeImageInfo.Add(mp3);
        nodeImageInfo.Add(pictures);
        nodeImageInfo.Add(video);
        return nodeImageInfo;
    }
}

Bind to Hierarchy Property Descriptor

You can create a tree view by binding the ItemsSource to the hierarchy property descriptors data source. To create a tree view using hierarchical data binding, set a hierarchical collection to the ItemsSource property, and then set the TargetType and ChildPropertyName property values in HierarchyPropertyDescriptors .

IMPORTANT

ItemsSource is an alternative mechanism to Nodes for adding content into the TreeView control. You cannot set both ItemsSource and Nodes at the same time. When you use ItemsSource, nodes are created internally, but you cannot access them from the Nodes property.

<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:syncfusion="clr-namespace:Syncfusion.Maui.TreeView;assembly=Syncfusion.Maui.TreeView"
             xmlns:treeviewengine="clr-namespace:Syncfusion.TreeView.Engine;assembly=Syncfusion.Maui.TreeView"
             xmlns:local="clr-namespace:GettingStarted;assembly=GettingStarted"
             x:Class="GettingStarted.MainPage">

  <ContentPage.BindingContext>
    <local:FileManagerViewModel x:Name="viewModel" />
  </ContentPage.BindingContext>
   <syncfusion:SfTreeView x:Name="treeView" 
                          ItemsSource="{Binding Folders}" >
       <syncfusion:SfTreeView.HierarchyPropertyDescriptors>
            <treeviewengine:HierarchyPropertyDescriptor TargetType="{x:Type local:Folder}" ChildPropertyName="Files"/>
            <treeviewengine:HierarchyPropertyDescriptor TargetType="{x:Type local:File}" ChildPropertyName="SubFiles"/>
        </syncfusion:SfTreeView.HierarchyPropertyDescriptors>
    </syncfusion:SfTreeView>

</ContentPage>
using Syncfusion.Maui.TreeView;
using Syncfusion.TreeView.Engine;
using System;

namespace GettingStarted
{
    public partial class MainPage : ContentPage
    {
        InitializeComponent();

       SfTreeView treeView = new SfTreeView();
       FileManagerViewModel viewModel = new FileManagerViewModel();
       treeView.ItemsSource = viewModel.Folders; 
       var propertyDescriptor = new HierarchyPropertyDescriptors();
       propertyDescriptor.Add(new Syncfusion.TreeView.Engine.HierarchyPropertyDescriptor() { TargetType = typeof(Folder), ChildPropertyName = "Files" });
       propertyDescriptor.Add(new Syncfusion.TreeView.Engine.HierarchyPropertyDescriptor() { TargetType = typeof(Files), ChildPropertyName = "SubFiles" });
       treeView.HierarchyPropertyDescriptors = propertyDescriptor;
       this.Content = treeView;
    }
}

Defining a template to expander and content view

By defining the ExpanderTemplate and ItemTemplate properties, a custom user interface (UI) can be created to display the data items for both expander and content view. It is applicable for both the Unbound and Bound mode data items.

NOTE

By default, the binding context for each tree view item will be the data model object for Bound Mode and TreeViewNode for Unbound Mode. However, you can change the binding context for tree view items in Bound Mode as TreeViewNode by defining the ItemTemplateContextType enumeration to Node, which is applicable for both ExpanderTemplate and ItemTemplate properties.

The following code example demonstrates how to customize your content view using the ItemTemplate and ExpanderTemplate property in both XAML and C#.

<ContentPage  xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:syncfusion="clr-namespace:Syncfusion.Maui.TreeView;assembly=Syncfusion.Maui.TreeView"
             xmlns:local="clr-namespace:GettingStarted.ViewModel"
             x:Class="GettingStarted.MainPage">
    <ContentPage.BindingContext>
       <local:FileManagerViewModel x:Name="viewModel"></local:FileManagerViewModel>
    </ContentPage.BindingContext>
    <ContentPage.Content>
       <syncfusion:SfTreeView x:Name="treeView" 
                              ItemsSource="{Binding ImageNodeInfo}"
                              ItemTemplateContextType="Node">
            <syncfusion:SfTreeView.ItemTemplate>
                <DataTemplate>
                           <Grid x:Name="grid" RowSpacing="0" 
                                 BackgroundColor="Transparent">
                              <Grid Padding="5,5,5,5">
                                  <Image Source="{Binding Content.ImageIcon}" 
                                         VerticalOptions="Center"
                                         HorizontalOptions="Center" 
                                         HeightRequest="35" 
                                         WidthRequest="35"/>
                              </Grid>
                              <Grid Grid.Column="1" 
                                    RowSpacing="1"
                                    Padding="1,0,0,0"
                                    VerticalOptions="Center">
                              <Label LineBreakMode="NoWrap" 
                                     Text="{Binding Content.ItemName}" 
                                     VerticalTextAlignment="Center"/>
                              </Grid>
                           </Grid>
                </DataTemplate>
            </syncfusion:SfTreeView.ItemTemplate>
            <syncfusion:SfTreeView.ExpanderTemplate>
                <DataTemplate>
                            <Image IsVisible="{Binding HasChildNodes,Converter={StaticResource IconVisibleConverter}}" 
                                   Source="{ Binding IsExpanded,Converter={StaticResource ExpanderIconConverter}}"
                                   VerticalOptions="Center" 
                                   HorizontalOptions="Center"/>
                </DataTemplate>
            </syncfusion:SfTreeView.ExpanderTemplate>
       </syncfusion:SfTreeView>
    </ContentPage.Content>
</ContentPage>
using Syncfusion.Maui.TreeView;

namespace GettingStarted
{
    public partial class MainPage : ContentPage
    {
        InitializeComponent();

        SfTreeView treeView = new SfTreeView();
        FileManagerViewModel viewModel = new FileManagerViewModel();
        treeView.ItemsSource = viewModel.ImageNodeInfo; 
        treeView.ChildPropertyName = "SubFiles";
        treeView.ItemTemplateContextType = ItemTemplateContextType.Node;
        treeView.ItemTemplate = new DataTemplate(() => 
        {
            HorizontalStackLayout stack = new HorizontalStackLayout();
            var imageIcon = new Image { WidthRequest = 24, HeightRequest = 24 };
            imageIcon.SetBinding(Image.SourceProperty, new Binding("Content.ImageIcon"));
            var itemName = new Label { FontSize = 15, VerticalTextAlignment=TextAlignment.Center, Padding=5 };
            itemName.SetBinding(Label.TextProperty, new Binding("Content.ItemName"));

            stack.Children.Add(imageIcon);
            stack.Children.Add(itemName);

            return stack;
        });

        treeView.ExpanderTemplate = new DataTemplate(()=>
        {
            var grid = new Grid();
            var expanderIcon = new Image();
            expanderIcon.SetBinding(Image.SourceProperty, new Binding("IsExpanded"));
            expanderIcon.SetBinding(Image.IsVisibleProperty, new Binding("HasChildNodes"));
            grid.Children.Add(expanderIcon);
            return grid;
        });

        this.Content = treeView;
    }
}

Download the entire source code from GitHub here.

.NET MAUI TreeView getting started BoundMode

Interacting with a tree view

The TreeView allows you to expand and collapse the nodes either by user interaction on the nodes or by programmatically. The expanding and collapsing interactions can be handled with the help of NodeCollapsing and NodeExpanding events.

You can define how the nodes to be expanded while loading the TreeView by using the AutoExpandMode property. Also, the TreeView allows you to set the restrictions whether expanding and collapsing of nodes can be performed only by tapping in expander view or in both expander view and content view by using the ExpandActionTarget property.

NOTE

the AutoExpandMode property is only applicable for bound mode. For Unbound mode you need to set IsExpanded property to true while creating the nodes, to be in expanded state while loading the TreeView.

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:syncfusion="clr-namespace:Syncfusion.Maui.TreeView;assembly=Syncfusion.Maui.TreeView"
             xmlns:local="clr-namespace:GettingStarted;assembly=GettingStarted"
             x:Class="GettingStarted.MainPage">
  <syncfusion:SfTreeView x:Name="treeView"
                         AutoExpandMode="AllNodesExpanded"
                         ExpandActionTarget="Node"/>
</ContentPage>
using Syncfusion.Maui.TreeView;
using Syncfusion.TreeView.Engine;

namespace GettingStarted
{
    public class MainPage : ContentPage
    {
        public MainPage()
        {
            InitializeComponent();
            SfTreeView treeView = new SfTreeView();
            treeView.AutoExpandMode = TreeViewAutoExpandMode.AllNodesExpanded;
            treeView.ExpandActionTarget = TreeViewExpandActionTarget.Node;
            this.Content = treeView;
        }
    }
}

Selection

The TreeView allows selecting the item by setting the SelectionMode property. Set the SelectionMode property to single, single-deselect, multiple, extended and none based on the requirements. Informations about the selected item can be tracked using the SelectedItem, CurrentItem and SelectedItems properties. Also, TreeView provides key board navigation support in WinUI and MacCatalyst platform.

It also allows changing the selection highlight color by using the SelectionBackground property. Additionally, for unbound mode, you can change the selection foreground color of the text by using the SelectionForeground property.

The selection operations can be handled with the help of SelectionChanging and SelectionChanged events.

<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:syncfusion="clr-namespace:Syncfusion.Maui.TreeView;assembly=Syncfusion.Maui.TreeView"
             xmlns:local="clr-namespace:GettingStarted.ViewModel"
             x:Class="GettingStarted.MainPage">

 <syncfusion:SfTreeView x:Name="treeView" 
                        SelectionMode="Single"
                        SelectionBackground="#EADDFF"
                        SelectionForeground="#1C1B1F"/>
</ContentPage>
using Syncfusion.Maui.TreeView;

namespace GettingStarted
{
    public class MainPage : ContentPage
    {
        SfTreeView treeView;
        public MainPage()
        {
            treeView = new SfTreeView();
            treeView.SelectionMode = TreeViewSelectionMode.Single;
            treeView.SelectionBackground = Color.FromHex("#EADDFF");
            treeView.SelectionForeground = Color.FromHex("#1C1B1F");
            this.Content=treeView;
        }
    }
}

Reset tree view items

You can reset the visible treeview items by using the ResetTreeViewItems method. If the parameter is null, all the visible treeview items will reset. If you are passing the data object as a parameter, a particular treeview item will reset.

treeView.ResetTreeViewItems();

Refresh view

You can refresh the view by using the RefreshView method. It will be used to refresh the items in the treeview at runtime while updating the view.

treeView.RefreshView();