Treeview control and setting individual items to checked

3 Answers 259 Views
TreeView
Victor
Top achievements
Rank 1
Victor asked on 23 Jun 2023, 08:46 PM
After adding items to the tree, I want to check an initial set of items and it is not working.  I have tried using "CheckedItems.Add()" and also setting the CheckedItems property to a list of objects.  Neither seems to work.  Am I doing something wrong?
Victor
Top achievements
Rank 1
commented on 23 Jun 2023, 09:23 PM

After more testing, setting the CheckItems property to a list of objects partially works but appears to have a bug.  If a child item is selected but not visible because the parent item is collapsed, it will not get checked even though it is in the array.  Also, using the CheckItems.Add() method doesn't seem to work at all.  I can work around this for now by making sure the tree is fully expanded (or at least the right nodes are expanded) before setting the CheckItems property.

3 Answers, 1 is accepted

Sort by
0
Didi
Telerik team
answered on 28 Jun 2023, 11:20 AM

Hello Victor,

The reason why the behavior happens on my side is because SelectedItems/CheckedItems collection is set first in xaml, then ItemsSource is set. I have logged this behavior on your behalf here: https://feedback.telerik.com/maui/1614332-treeview-items-are-coerced-immediately-when-selecteditems-and-checkeditems-collections-are-set-before-itemssource 

As a solution set first the ItemsSource, then the SelectedItems/CheckedItems 

<telerik:RadTreeView x:Name="treeView" 
                         CheckBoxMode="Recursive" Grid.Row="1"
                              ItemsSource="{Binding Items}"
                         SelectedItems="{Binding CheckedItems, Mode=TwoWay}">

I have tested inside the .NET MAUI CollectionView and adding items programmatically to the SelectedItems, still there isn't an indication for selection and collections is empty.

Regards,
Didi
Progress Telerik

Love the Telerik and Kendo UI products and believe more people should try them? Invite a fellow developer to become a Progress customer and each of you can get a $50 Amazon gift voucher.

Paul
Top achievements
Rank 1
Iron
commented on 04 Sep 2023, 12:56 AM

Hi Didi,

This doesn't appear to fix the problem for the "CheckedItems" collection when the Treeview contains nested items (eg. Items/Children class used in the examples) and then programatically populating the CheckedItems collection.

Only the parent items are checked and none of the nested items are checked even though the CheckedItems collection contains the Parent and Children items.

Didi
Telerik team
commented on 04 Sep 2023, 02:14 PM

Hi Paul,

When programmatically adding one item to the collection, it doesn't add its children automatically. This operation is not recursive. You have to add them manually to the bound collection. 

When checking items through the UI and for example bind the checked items collection to the ListView, The control is populated with the items, for example:

<Grid RowDefinitions="*,*">
    <telerik:RadTreeView x:Name="treeView" 
                        ItemsSource="{Binding Items}"
                            CheckedItems="{Binding Checked}"
                        CheckBoxMode="Recursive">
        <telerik:TreeViewDescriptor ItemsSourcePath="Children" DisplayMemberPath="Name"
                                TargetType="{x:Type local:Item}"/>
    </telerik:RadTreeView>
    <telerik:RadListView Grid.Row="1" x:Name="list" ItemsSource="{Binding CheckedItems, Source={x:Reference treeView}}"/>
</Grid>

 

Paul
Top achievements
Rank 1
Iron
commented on 05 Sep 2023, 01:42 AM

Hi Didi,

Thanks for you response. I'm still not sure how I can achieve what I need to do with populating the TreeView from your example.

My use case is that when the page loads I need to display a treeview with a list of items where some of the items are already checked when the control has rendered onscreen. The user will then have the ability to check more items or uncheck items and then save the list back to a database.

At the moment I can only get the treeview to display a checked item at the parent level, I can not workout how to also display child items that are checked.

This image shows what I currently get:

 

This is an example of the sort of thing I am trying to achieve:

This is my XAML page:


<?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:telerik="http://schemas.telerik.com/2022/xaml/maui"
             xmlns:local="clr-namespace:InterfaceAdminToolV2.ViewModel"
			 x:DataType="local:MainPageViewModel"
             x:Class="InterfaceAdminToolV2.View.MainPage">

	<VerticalStackLayout Spacing="30">
		<telerik:RadTreeView x:Name="treeView"
							 HeightRequest="500"
							 ItemsSource="{Binding Items}"
							 CheckBoxMode="Recursive"
							 CheckedItems="{Binding CheckedItems, Mode=TwoWay}">

			<telerik:TreeViewDescriptor TargetType="{x:Type local:Item}"
			                            DisplayMemberPath="Name"
			                            ItemsSourcePath="Children" />
		</telerik:RadTreeView>

		<!-- control just to debug to see what has been checked-->
		<telerik:RadTreeView x:Name="checkedTree"
		                     HeightRequest="500"
		                     ItemsSource="{Binding CheckedItems, Source={x:Reference treeView}}"
		                     CheckBoxMode="Recursive">

			<telerik:TreeViewDescriptor TargetType="{x:Type local:Item}"
			                            DisplayMemberPath="Name"
			                            ItemsSourcePath="Children" />
		</telerik:RadTreeView>
	</VerticalStackLayout>
</ContentPage>

This is my viewmodel:


using System.Collections.ObjectModel;
namespace InterfaceAdminToolV2.ViewModel;

public partial class MainPageViewModel : ViewModelBase
{
    [ObservableProperty]
    private ObservableCollection<Item> items;

    [ObservableProperty]
    private ObservableCollection<Item> checkedItems;

    public MainPageViewModel()
    {
        Items = new ObservableCollection<Item>();
        Items.Add(new Item
        {
            Name = "My Projects",
            Children = new List<Item>()
            {
                new Item()
                {
                    Name = "Using latest Telerik .NET MAUI controls",
                    Children = new ObservableCollection<Item>()
                    {
                        new Item { Name = "TreeView"},
                        new Item() {Name = "Calendar"},
                        new Item() {Name = "RichTextEditor"},
                        new Item(){Name = "PdfViewer"},
                        new Item(){Name = "SlideView"},
                        new Item() {Name = "Chat"},
                    }
                },
                new Item { Name = "Blank project" }
            }
        });
        Items.Add(new Item()
        {
            Name = "Shared Documents",
            Children = new List<Item>()
            {
                new Item()
                {
                    Name = "Reports",
                    Children = new List<Item>()
                    {
                        new Item(){Name = "October"},
                        new Item() {Name = "November"},
                        new Item(){Name = "December"}
                    }
                }
            }
        });

        var existingSelectedItems = Items.SkipLast(1).ToList();
        CheckedItems = new ObservableCollection<Item>(existingSelectedItems);
    }
}

public class Item
{
    public string Name { get; set; }
    public IList<Item> Children { get; set; } = new List<Item>();

    public bool HasChildren => Children.Any();
}

Didi
Telerik team
commented on 07 Sep 2023, 04:01 PM

Hi Paul,

You have to iterate through the child nodes for the concrete parent item and add them to the CheckedItems collection. You have to manually populate the collection with the items.

Daniel
Top achievements
Rank 1
Iron
commented on 11 Sep 2023, 04:18 PM | edited

Hi Didi.

I have the same situation, I would like to know how is possible to do that.
0
Didi
Telerik team
answered on 13 Sep 2023, 12:10 PM

Hi all,

TreeView control provides CheckedItems collection. You can add/remove items programmatically. You have to iterate through the child nodes for the concrete parent item and add them to the CheckedItems collection. You have to manually populate the collection with the items.

Here is a sample

<Grid RowDefinitions="Auto,*">
    <VerticalStackLayout >
        <Button Clicked="Button_Clicked" Text="Add Item"/>
        <Button Clicked="Button_Clicked_1" Text="Remove item"/>
    </VerticalStackLayout>
    
    <telerik:RadTreeView x:Name="treeView" Grid.Row="1"
                    AutomationId="treeView" CheckBoxMode="Recursive"
                            CheckedItems="{Binding CheckedItems}"
                    ItemsSource="{Binding Items}">
        <telerik:TreeViewDescriptor DisplayMemberPath="Name"
                            ItemsSourcePath="Children"
                            TargetType="{x:Type local:Item}" />
    </telerik:RadTreeView>
</Grid>

 

public partial class MainPage : ContentPage
{
    ViewModel vm;

    public MainPage()
    {
        InitializeComponent();
        this.vm = new ViewModel();
        this.BindingContext = this.vm;
    }

    private void Button_Clicked(object sender, EventArgs e)
    {
        this.vm.CheckedItems.Add(this.vm.Items[0]);

        foreach (var node in this.vm.Items)
        {
            this.vm.CheckedItems.Add(node);

            foreach (var cityNode in node.Children)
            {
                this.vm.CheckedItems.Add(cityNode);
            }
        }
    }


    private void Button_Clicked_1(object sender, EventArgs e)
    {
        if (this.vm.CheckedItems.Count > 0)
        {
            this.vm.CheckedItems.Remove(this.vm.Items[0]);
        }
        else return;
    }
}
public class ViewModel : NotifyPropertyChangedBase
{
    public ViewModel()
    {
        Items = new ObservableCollection<Item>();
        CheckedItems = new ObservableCollection<Item>();
        Items.Add(new Item("My Projects")
        {
            Children = new List<Item>()
            {
                new Item("Using latest Telerik .NET MAUI controls")
                {
                    Children = new ObservableCollection<Item>()
                    {
                        new Item("TreeView"),
                        new Item("Calendar"),
                        new Item("RichTextEditor"),
                        new Item("PdfViewer"),
                        new Item("SlideView"),
                        new Item("Chat"),
                    }
                },
                new Item("Blank project")
            }
        });
        Items.Add(new Item("Shared Documents")
        {
            Children = new List<Item>()
            {
                new Item("Reports")
                {
                    Children = new List<Item>()
                    {
                        new Item("October"),
                        new Item("November"),
                        new Item("December")
                    }
                }
            }
        });
    }
    public ObservableCollection<Item> Items { get; set; }
    private ObservableCollection<Item> checkedItems;
    public ObservableCollection<Item> CheckedItems
    {
        get => this.checkedItems;
        set
        {
            if (this.checkedItems != value)
            {
                this.checkedItems = value;

                this.OnPropertyChanged();
            }
        }
    }
}
public class Item
{
    public Item(string name)
    {
        this.Name = name;
        this.Children = new ObservableCollection<Item>();
    }

    public string Name { get; set; }
    public IList<Item> Children { get; set; }
}

Note that how to iterate through items is a custom development. You have the items collection and checked items collection. How to manage these collections requires custom logic implementation. 

Regards,
Didi
Progress Telerik

A brand new .NET MAUI course was just added to the Virtual Classroom. The training course is developed to help you get started with the Telerik UI for .NET MAUI components and features. It aims to put you in the shoes of an engineer who adds new features to an existing application. You can check it out at https://learn.telerik.com
Paul
Top achievements
Rank 1
Iron
commented on 11 Oct 2023, 12:17 AM

I'm trying to set the CheckedItems on initial load of the TreeView items and have the CheckBox for selected nodes ticked when the page loads.

I am able to set the CheckedItems collection but it does not set the TreeView node CheckBoxes to true and if I click the checkbox for an item already in the CheckedItems collection it adds the same item again.

Paul
Top achievements
Rank 1
Iron
commented on 11 Oct 2023, 04:17 AM | edited

This is example code of the result I'm getting.

I want the children items to have their checkbox ticked if there are part of the CheckedItems collection.

Page xaml

<?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:telerik="http://schemas.telerik.com/2022/xaml/maui"
			 xmlns:viewmodel="clr-namespace:InterfaceAdminToolV2.ViewModel"
			 x:Class="InterfaceAdminToolV2.View.DropDownPage"
             x:DataType="viewmodel:DropDownPageViewModel">

	<Grid RowDefinitions="Auto,*, *">
		

		<telerik:RadTreeView x:Name="treeView" Grid.Row="1"
		                     AutomationId="treeView" 
							 SelectionMode="None"
		                     ItemsSource="{Binding Books}"
							 CheckBoxMode="Independent"
		                     CheckedItems="{Binding CheckedItems}">

			<telerik:TreeViewDescriptor DisplayMemberPath="Title"
			                            ItemsSourcePath="Authors"
			                            TargetType="{x:Type viewmodel:Book}" />
		</telerik:RadTreeView>
		<VerticalStackLayout Grid.Row="2">
			<Label Text="CheckedItem's collection" />
			<telerik:RadListView  ItemsSource="{Binding CheckedItems}">
				<telerik:RadListView.ItemTemplate>
					<DataTemplate>
						<telerik:ListViewTextCell x:DataType="viewmodel:Book" Text="{Binding Id}"
						                          Detail="{Binding Title}"
						                          TextColor="Black"
						                          DetailColor="Gray" />
					</DataTemplate>
				</telerik:RadListView.ItemTemplate>
			</telerik:RadListView>
		</VerticalStackLayout>
	</Grid>

</ContentPage>

 

ViewModel and TreeView object


using System.Collections.ObjectModel;
using Telerik.Maui.Controls;

namespace InterfaceAdminToolV2.ViewModel;

public partial class DropDownPageViewModel : NotifyPropertyChangedBase
{
    public DropDownPageViewModel()
    {
        Books = new ObservableCollection<Book>();

        Books.Add(new Book(1, "First Book")
        {
            Authors = new List<Book>
        {
            new Book(99, "Sam Dob"),
            new Book(23, "Mark Semt")
        }
        }
        );
        
        Books.Add(new Book(2, "Shared Documents"));
        Initialize();
    }

    private void Initialize()
    {
        CheckedItems = new ObservableCollection<Book>();

        foreach (var node in Books)
        {
            CheckedItems.Add(node);

            foreach (var nodeAuthor in node.Authors)
            {
                    CheckedItems.Add(nodeAuthor);
            }
        }

    }

    private ObservableCollection<Book> checkedItems;

    public ObservableCollection<Book> CheckedItems
    {
        get => this.checkedItems;
        set
        {
            if (this.checkedItems != value)
            {
                this.checkedItems = value;
                this.OnPropertyChanged();
            }
        }
    }
    public ObservableCollection<Book> Books { get; set; }
}

public class Book
{
    public Book(int id, string title)
    {
        this.Id = id; this.Title = title;
        this.Authors = new List<Book>();
    }

    public int Id { get; set; }
    public string Title { get; set; }
    public IList<Book> Authors { get; set; }
}

 

0
Paul
Top achievements
Rank 1
Iron
answered on 11 Oct 2023, 11:29 PM
Upgrading Telerik.UI.for.Maui nuget package to version "6.3.0" has resolved the issue of Child items in the TreeView being ticked when added to the CheckedItems collection.
Tags
TreeView
Asked by
Victor
Top achievements
Rank 1
Answers by
Didi
Telerik team
Paul
Top achievements
Rank 1
Iron
Share this question
or