Skip to main content Skip to footer

How to Build a C# .NET TreeGrid Control

Quick Start Guide
What You Will Need

Visual Studio

ComponentOne WPF Edition

Controls Referenced

FlexGrid for WPF

Tutorial Concept This tutorial shows how to create a complete TreeGrid control using ComponentOne FlexGrid for WPF.

Have you ever struggled with managing complex hierarchical data? The TreeGrid control organizes it all with ease!

Whether you're dealing with organizational charts, file systems, product categories, or project management, it is essential to present data in an intuitive and easily navigable manner. A TreeGrid control offers a powerful solution by transforming complex structures into an interactive and visually engaging experience, making it easier for end users to work with it efficiently.

ComponentOne includes a DataGrid control named FlexGrid, which is known for its performance and customizability. It can be used as a TreeGrid, making it easy to display a tree structure by directly binding to a hierarchical data source, as shown in the screenshot below.

TreeGrid

In this blog post, we will learn how to create a TreeGrid representing the various stages of a Software Development Plan consisting of multiple tasks and their subtasks. We will implement this following the steps below:

  1. Setup a WPF App with the FlexGrid Control
  1. Setup the Hierarchical DataSource
  1. Bind the Hierarchical DataSource to the FlexGrid

Ready to Get Started? Download ComponentOne Today!

Setup a WPF App with the FlexGrid Control

Begin by creating a new 'WPF Application' project targeting .NET 8 in Visual Studio 2022.

Once the project is created, install the C1.WPF.Grid NuGet package in the project. After installing the package, add the FlexGrid control to the MainWindow.xaml and customize its columns to display the Task Name, Duration, and Completion Percentage. Below is the XAML code to achieve this:

<Window.Resources>
        <DataTemplate x:Key="ProgressBarTemplate">
            <Grid>
                <ProgressBar Value="{Binding PercentComplete, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}" Margin="5 5 5 5" Minimum="0" Maximum="100" BorderBrush="Transparent" Background="Transparent" Foreground="LightBlue"/>
                <TextBlock Text="{Binding PercentComplete, StringFormat={}{0}%}" HorizontalAlignment="Center" VerticalAlignment="Center" />
            </Grid>
        </DataTemplate>
    </Window.Resources>
    <Grid>
        <c1:FlexGrid Name="flexTree" TreeIndent="30" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" AutoGenerateColumns="False">
            <c1:FlexGrid.Columns>
                <c1:GridColumn Width="5*" x:Name="TaskName" Binding="TaskName" Header="Task"/>
                <c1:GridColumn Width="2*" x:Name="Duration" Binding="Duration" Header="Duration (Days)"/>
                <c1:GridColumn Width="5*" x:Name="PercentComplete" Binding="PercentComplete" Header="% Complete" CellTemplate="{StaticResource ProgressBarTemplate}"/>
            </c1:FlexGrid.Columns>
        </c1:FlexGrid>
    </Grid>
</Window>

Setup the Hierarchical Data Source

To create a TreeGrid, a hierarchical data source is required. Let’s define a class named ProjectTask that includes properties for all the relevant details of a task in the Software Development Plan. This class will also feature a SubTasks property, a collection of ProjectTask objects to store subtasks in a hierarchical manner.

Below is the C# code to achieve this:

public class ProjectTask : INotifyPropertyChanged
{
    private string? _taskName;
    public string? TaskName { get { return _taskName; } set { _taskName = value; OnPropertyChanged(nameof(TaskName)); } }

    private float? _percentComplete;
    public float? PercentComplete { get { return _percentComplete; } set { _percentComplete = value; OnPropertyChanged(nameof(PercentComplete)); } }

    private int? _duration;
    public int? Duration { get { return _duration; } set { _duration = value; OnPropertyChanged(nameof(Duration)); } }

    private ObservableCollection<ProjectTask>? _subTasks;
    public ObservableCollection<ProjectTask>? SubTasks { get { return _subTasks; } set { _subTasks = value; OnPropertyChanged(nameof(SubTasks)); } }

    public event PropertyChangedEventHandler? PropertyChanged;
    protected virtual void OnPropertyChanged(string propertyName)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

For the data, we are using a JSON file containing sample data representing the various stages of a Software Development Plan. Below is a C# code snippet showcasing a portion of the sample data:

public static ObservableCollection<ProjectTask> GetProjectTaskData()
{
    var data = new ObservableCollection<ProjectTask>
    {
        new ProjectTask()
        {
            TaskName = "Software Requirement Analysis",
            PercentComplete = 100,
            Duration = 15,
            SubTasks =
            [
                new ProjectTask()
                {
                    TaskName = "Requirement Analysis",
                    PercentComplete = 100,
                    Duration = 6
                },
                new ProjectTask()
                {
                    TaskName = "Writing Specification",
                    PercentComplete = 100,
                    Duration = 7
                },
                new ProjectTask()
                {
                    TaskName = "Review Specification",
                    PercentComplete = 100,
                    Duration = 2
                }
            ]
        },
    };
}

Bind the Hierarchical Data Source to FlexGrid

In the final step, bind the DataSource created in the previous step to the FlexGrid using its ItemsSource property. By default, the FlexGrid does not generate a TreeGrid. To enable it, you must set the ChildItemsPath property of the FlexGrid to the field from the DataSource containing the hierarchical children, which is SubTasks in our case.

Below is the C# code:

public MainWindow()
{
    InitializeComponent();

    //Set ChildItemsPath and ItemsSource
    flexTree.ChildItemsPath = "SubTasks";
    flexTree.ItemsSource = ProjectTask.GetProjectTaskData();
}

After implementing all the steps, the final application works as shown in the GIF below:

Final App

Download the sample project to implement the TreeGrid functionality.

Ready to try it out? Download ComponentOne Today!

Conclusion

In this blog post, we created a TreeGrid using the FlexGrid control with a few simple steps. We hope you find the demo helpful. The FlexGrid control offers numerous other features that can simplify your development process. You can learn more by checking out its documentation.

Feel free to try it out and leave your feedback or questions in the comments section. Happy Coding!

comments powered by Disqus