3 Steps to Lazy Load Data in WPF TreeView in MVVM Pattern
Tags: csharp, dotnet, productivity
Published: 2021-03-12 12:24:01

---
title: 3 Steps to Lazy Load Data in WPF TreeView in MVVM Pattern
published: true
date: 2021-02-11 11:56:34 UTC
tags: csharp, dotnet, productivity
canonical_url: https://www.syncfusion.com/blogs/post/3-steps-to-lazy-load-data-in-wpf-treeview-mvvm.aspx
cover_image: https://www.syncfusion.com/blogs/wp-content/uploads/2021/02/3-Steps-to-Lazy-Load-Data-in-WPF-TreeView-672x372.png
---

Loading a large amount of data by the default procedure in our [WPF TreeView](https://www.syncfusion.com/wpf-ui-controls/treeview) control can take time and consume many resources. But a little-known trick in Windows Presentation Framework (WPF) is lazy loading, which gives you the ability to load data on demand quickly and without using expensive resources to hold all the data.

The WPF TreeView supports lazy loading, where TreeView loads the child nodes on demand when they are requested. The child nodes can be loaded from services or databases when the parent node is expanded. For example, if you are developing an application like the file explorer TreeView in Windows, a lot of time will be taken when you loop all the drives and files. In such cases, the best way to load the child nodes is to perform lazy loading (load on demand) when the child nodes are expanded.

In this article, we are going to implement lazy loading using MVVM pattern in just three steps, with the use case of a Windows file browser:

1. Create a TreeView and bind it with data.
2. Create load-on-demand command in the ViewModel.
3. Bind the LoadOnDemandCommand of TreeView with the command created in the ViewModel.

## Creating a TreeView and binding it with data

Create a class named **Directory** with the property **Name**, which denotes the name of the drive or directory, and the property **FullName**, which denotes the full path of the directory. The Directory class should be derived from [NotificationObject](https://help.syncfusion.com/cr/wpf/Syncfusion.Windows.Shared.NotificationObject.html), which has the implementation for the **INotifyPropertyChanged** interface **.**

**Model**

```csharp
public class Directory : NotificationObject
{
    private string name;
    private bool hasChildNodes;
    private string fullName;

    public string Name
    {
       get { return name; }
       set
       {
           name = value;
           RaisePropertyChanged("Name");
       }
     }

     public string FullName
     {
        get { return fullName; }
        set
        {
            fullName = value;
            RaisePropertyChanged("FullName");
        }
     }

     public bool HasChildNodes
     {
         get { return hasChildNodes; }
         set
         {
             hasChildNodes = value;
             RaisePropertyChanged("HasChildNodes");
         }
    }    
}
```

Next, create a **ViewModel** class with the **Directories** property. This property holds the driver details of the system to create a file-exploring TreeView. When a user expands the driver, the child nodes will be loaded on demand.

**ViewModel**

```csharp
public class ViewModel
{
    public ObservableCollection<Directory> Directories { get; set; }
        
    public ViewModel()
    {
       this.Directories = this.GetDrives();
    }         

    private ObservableCollection<Directory> GetDrives()
    {
        ObservableCollection<Directory> directories = new ObservableCollection<Directory>();
        DriveInfo[] driveInfos = DriveInfo.GetDrives();
        foreach (DriveInfo driveInfo in driveInfos)
        {
           directories.Add(new Directory() { Name = driveInfo.Name, FullName = driveInfo.Name, HasChildNodes = true });
        }
       return directories;
    }
}
```

After creating the ViewModel class:

1. Add the ViewModel class as DataContext for Window.
2. Bind the **Directories** property from the ViewModel to the [ItemsSource](https://help.syncfusion.com/cr/wpf/Syncfusion.UI.Xaml.TreeView.SfTreeView.html#Syncfusion_UI_Xaml_TreeView_SfTreeView_ItemsSource) property of TreeView.
3. Set the [ItemTemplate](https://help.syncfusion.com/cr/wpf/Syncfusion.UI.Xaml.TreeView.SfTreeView.html#Syncfusion_UI_Xaml_TreeView_SfTreeView_ItemTemplate) property of TreeView to display the content. Here, Label is added, and the Content of Label is bound to the **Name**

**XAML**

```html
<Window.DataContext>
    <local:ViewModel/>
</Window.DataContext>       
 <Syncfusion:SfTreeView ItemsSource="{Binding Directories}"
                        ItemHeight="30"
                        HorizontalAlignment="Left" 
                        IsAnimationEnabled="True"
                        Margin="25,0,0,0" 
                        VerticalAlignment="Top" 
                        Width="250">
     <Syncfusion:SfTreeView.ItemTemplate>
       <DataTemplate>
          <Label
             VerticalContentAlignment="Center"
             Content="{Binding Name}"
             FocusVisualStyle="{x:Null}"
             />
       </DataTemplate>
    </Syncfusion:SfTreeView.ItemTemplate>
</Syncfusion:SfTreeView>
```

## Creating load-on-demand command in the ViewModel

Now, TreeView will be displayed with two nodes. Let’s enable lazy loading in TreeView by creating [LoadOnDemandCommand](https://help.syncfusion.com/cr/wpf/Syncfusion.UI.Xaml.TreeView.SfTreeView.html#Syncfusion_UI_Xaml_TreeView_SfTreeView_LoadOnDemandCommand). This will control the expander visibility based on the return value of the CanExecute command. The loading of child nodes is done in the Execute command.

```csharp
public class ViewModel
{ 
public ICommand TreeViewLoadOnDemandCommand { get; set; }

public ViewModel()
  {             
    TreeViewLoadOnDemandCommand = new DelegateCommand(ExecuteOnDemandLoading, CanExecuteOnDemandLoading);
  }         
}
```

### Handling TreeNode expander visibility in the CanExecute method of command

Return true from the CanExecute method to show the expander for the node if the node has child nodes, or else return false. Here, the visibility of the expander is returned based on the HasChildNodes property in the Directory. The HasChildNodes property is set based on whether the directory has subdirectories or files when the node is populated.

```csharp
private bool CanExecuteOnDemandLoading(object sender)
{
   var hasChildNodes = ((sender as TreeViewNode).Content as Directory).HasChildNodes;
   if (hasChildNodes)
     return true;
   else
     return false;
}
```

### Lazy loading of TreeView in Execute method of command

Load the child nodes in the Execute method. Call the Execute method when a user expands the tree node.

Show or hide the busy indicator in the place of the expander by setting [TreeViewNode.ShowExpanderAnimation](https://help.syncfusion.com/cr/wpf/Syncfusion.UI.Xaml.TreeView.Engine.TreeViewNode.html#Syncfusion_UI_Xaml_TreeView_Engine_TreeViewNode_ShowExpanderAnimation) until the data is fetched.

Retrieve the inner directories and files from the **GetDirectories** method. Populate the child nodes by calling the [TreeViewNode.PopulateChildNodes](https://help.syncfusion.com/cr/wpf/Syncfusion.UI.Xaml.TreeView.Engine.TreeViewNode.html#Syncfusion_UI_Xaml_TreeView_Engine_TreeViewNode_PopulateChildNodes_System_Collections_IEnumerable_) method by passing the child items collection that is obtained from **GetDirectories**.

During command execution, the expanding operation will not be handled by TreeView. So, you have to set the [TreeViewNode.IsExpanded](https://help.syncfusion.com/cr/wpf/Syncfusion.UI.Xaml.TreeView.Engine.TreeViewNode.html#Syncfusion_UI_Xaml_TreeView_Engine_TreeViewNode_IsExpanded) property to true to expand the tree node after populating child nodes.

You should skip the population of child items every time the node expands, based on the [TreeViewNode.ChildNodes](https://help.syncfusion.com/cr/wpf/Syncfusion.UI.Xaml.TreeView.Engine.TreeViewNode.html#Syncfusion_UI_Xaml_TreeView_Engine_TreeViewNode_ChildNodes) count.

```csharp
private void ExecuteOnDemandLoading(object obj)
{
   var node = obj as TreeViewNode;

   // Skip the repeated population of child items every time the node expands.
   if (node.ChildNodes.Count > 0)
   {
      node.IsExpanded = true;
      return;
   }
   //Animation starts for expander to show progress of load on demand.
   node.ShowExpanderAnimation = true;            
   Directory Directory = node.Content as Directory;
   Application.Current.MainWindow.Dispatcher.BeginInvoke(DispatcherPriority.Background,
    new Action(async () =>
    {
      await Task.Delay(1000);                

      //Fetching child items to add.
      var items = GetDirectories(Directory);

      // Populating child items for the node in on demand.
      node.PopulateChildNodes(items);
      if (items.Count() > 0)
         //Expand the node after child items are added.
         node.IsExpanded = true;

      //Stop the animation after load on demand is executed. If animation is not stopped, it remains after execution of load on demand.
      node.ShowExpanderAnimation = false;                   

     }));
    }
    public IEnumerable<Directory> GetDirectories(Directory directory)
    {
       var directories = new ObservableCollection<Directory>();
       var dirInfo = new DirectoryInfo(directory.FullName);
           
       foreach (DirectoryInfo directoryInfo in dirInfo.GetDirectories())
       {
         try
         {
           directories.Add(new Directory()
           {   
               Name = directoryInfo.Name,
               HasChildNodes = directoryInfo.GetDirectories().Length > 0 || directoryInfo.GetFiles().Length > 0,
               FullName = directoryInfo.FullName
             });
          }
        catch { }
       }
       foreach (FileInfo fileInfo in dirInfo.GetFiles())
       {
         directories.Add(new Directory()
          {
             Name = fileInfo.Name,
             HasChildNodes = false,
             FullName = fileInfo.FullName
           });
        }
     return directories;
}
```

## Binding load on-demand command of TreeView with ViewModel command

Finally, bind the [TreeView.LoadOnDemandCommand](https://help.syncfusion.com/cr/wpf/Syncfusion.UI.Xaml.TreeView.SfTreeView.html#Syncfusion_UI_Xaml_TreeView_SfTreeView_LoadOnDemandCommand) property to the ViewModel’s TreeViewLoadOnDemandCommand property.

That’s all. Lazy loading implementation is completely done for WPF TreeView.

```html
<Syncfusion:SfTreeView ItemsSource="{Binding Directories}"
                       LoadOnDemandCommand="{Binding TreeViewLoadOnDemandCommand}"
                       ItemHeight="30"
                       HorizontalAlignment="Left" 
                       IsAnimationEnabled="True"
                       Margin="25,0,0,0" 
                       VerticalAlignment="Top" 
                       Width="250">
            <Syncfusion:SfTreeView.ItemTemplate>
                <DataTemplate>
                    <Label
                        VerticalContentAlignment="Center"
                        Content="{Binding Name}"
                        FocusVisualStyle="{x:Null}"
                        />
                    </DataTemplate>
            </Syncfusion:SfTreeView.ItemTemplate>
        </Syncfusion:SfTreeView>
```

![Lazy loading in Syncfusion WPF TreeView](https://www.syncfusion.com/blogs/wp-content/uploads/2021/02/Lazy-loading-in-Syncfusion-WPF-TreeView.gif)<figcaption>Lazy loading in Syncfusion WPF TreeView</figcaption>

## Resources

The complete project explained in this blog is available in this [GitHub repository](https://github.com/SyncfusionExamples/how-to-perform-lazy-loading-in-wpf-treeview). Also, our demos are now available in the [Microsoft Store](https://www.microsoft.com/en-us/p/syncfusion-wpf-controls-examples/9n99kdhrff6g), and our .NET Core demos are available in the [App Center](https://install.appcenter.ms/orgs/syncfusion-demos/apps/wpf-demos/distribution_groups/release).

## Conclusion

I hope, you enjoyed this blog about the procedure to perform lazy loading in the [Syncfusion WPF TreeView control](https://www.syncfusion.com/wpf-ui-controls/treeview) using MVVM pattern. You can learn more about WPF TreeView’s features [here](https://help.syncfusion.com/wpf/treeview/overview).

Syncfusion has over 90 essential WPF controls like [DataGrid](https://www.syncfusion.com/wpf-ui-controls/datagrid), [Charts](https://www.syncfusion.com/wpf-ui-controls/charts), [Diagram](https://www.syncfusion.com/wpf-ui-controls/diagram), and [PDF Viewer](https://www.syncfusion.com/wpf-ui-controls/pdf-viewer). Give these controls a shot by downloading the setup from our latest release.

For existing customers, the newest version is available for download from the [license and downloads](https://www.syncfusion.com/account/downloads) page. If you are not yet a customer, you can try our 30-day [free trial](https://www.syncfusion.com/downloads) to check out these new features.

Also, if you wish to send us feedback or would like to submit any questions, please feel free to post them in the comments section of this blog post. You can also contact us through our [support forums](https://www.syncfusion.com/forums), [feedback portal](https://www.syncfusion.com/feedback), or [Direct-Trac support system](https://www.syncfusion.com/support/directtrac/incidents).