Дополнительная информация в нодах TreeView



            tvFavorites.ChildrenGetter = obj => { return ((MyData)obj).Children; };
            tvFavorites.ParentGetter = obj => ((MyData)obj).Parent;
            tvFavorites.CanExpandGetter = obj => true;
            tvFavorites.Roots = new List<MyData>() { new MyData() { DisplayName = "Избранное" } };
            MyData favoritesRootNode = (MyData)tvFavorites.Roots[0];

Выдаёт ошибку: CS0021|Не удается применить индексирование через [] к выражению типа “IEnumerable”.

:arrow_down:

И еще в вашем коде не понятно, как добавляются сабитемы. Если это демонстрационный пример, то надо писать более детальные комментарии, чтобы даже ребёнок смог разобраться. А так это выглядит, как какая-то магия.

Они изначально существуют в иерархии объектов, это ж файловая система. Точнее они подгружаются при открытии элементов-папок. Поэтому достаточно этого


Если надо во время работы программы постепенно добавлять (например, кнопка “Добавить”), то надо сделать то, что нужно, с каким-то объектом, чтоб у него появились потомки (например, просто obj.Children.Add()) и

на его корне.

там же получается дерево из моих MyData и там нету никакого RefreshObjecta :man_shrugging:
а если так:

            tvFavorites.ChildrenGetter = obj => { return ((MyData)obj).Children; };
            tvFavorites.ParentGetter = obj => ((MyData)obj).Parent;
            tvFavorites.CanExpandGetter = obj => true;
            tvFavorites.Roots = new List<MyData>() { new MyData() { DisplayName = "Избранное" } };
            favoritesRootNode = tvFavorites.Roots.Cast<MyData>().ToList()[0];
            favoritesRootNode.Children.Add(new MyData(){ DisplayName = "ррр" });
            tvFavorites.RefreshObject(favoritesRootNode);

то в избранное ничего не добавляется.

Должно работать.

Тут даже без рефреша если ноды не раскрыты сразу.

        public class Item
        {
            public string Name;
            public Category Category;

            public Item(string name, Category category)
            {
                Name = name;
                Category = category;
            }
        }

        public class Category
        {
            public string Name;
            public List<Item> Items = new List<Item>();
        }
            tvItems.CanExpandGetter = obj => obj is Category;
            tvItems.ChildrenGetter = obj => ((Category)obj).Items;
            tvItems.ParentGetter = obj =>
            {
                if (obj is Item)
                {
                    return ((Item)obj).Category;
                }
                return null;
            };

            var category = new Category { Name = "Category 1" };
            tvItems.Roots = new[] { category };

            category.Items.Add(new Item("Item 1", category));
            category.Items.Add(new Item("Item 2", category));
        private void btnAdd_Click(object sender, EventArgs e)
        {
            var category = tvItems.Roots.Cast<Category>().ToArray()[0];

            category.Items.Add(new Item("Item 3", category));

            tvItems.RefreshObject(category);
        }

не пойму, чем это отличается от моего

        public class MyData
        {
            public List<MyData> Children { get; } = new List<MyData>();
            public MyData Parent { get; set; }
            public string DisplayName { get; set; }
        }

            tvFavorites.ChildrenGetter = obj => { return ((MyData)obj).Children; };
            tvFavorites.ParentGetter = obj => ((MyData)obj).Parent;
            tvFavorites.CanExpandGetter = obj => { return ((MyData)obj).Children.Count > 0; };
            tvFavorites.Roots = new List<MyData>() { new MyData() { DisplayName = "Избранное" } };
            favoritesRootNode = tvFavorites.Roots.Cast<MyData>().ToList()[0];
            favoritesRootNode.Children.Add(new MyData(){ DisplayName = "ррр" });
            tvFavorites.RefreshObject(favoritesRootNode);
          

Я понял. Я парент не ставлю.

            favoritesRootNode.Children.Add(new MyData(){ DisplayName = "ррр", Parent = favoritesRootNode });

Тогда сабитем добавляется. Но при распахивании избранного, ppp находится не в избранном, а рядом с ним.

У меня работает этот код.

image

В столбцах менял только это

image

и у TreeListView HeaderStyle None.

Screenshot_trim
:man_shrugging: :unamused:
избранное можно сворачивать и разворачивать, хотя + нету.

Может какие-то настройки про это изменены?

Я бы пересоздал или проверил что в .Designer.cs

            // 
            // tvFavorites
            // 
            this.tvFavorites.AllColumns.Add(this.olvColumn1);
            this.tvFavorites.CellEditUseWholeCell = false;
            this.tvFavorites.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] {
            this.olvColumn1});
            this.tvFavorites.HeaderStyle = System.Windows.Forms.ColumnHeaderStyle.None;
            this.tvFavorites.HideSelection = false;
            this.tvFavorites.Location = new System.Drawing.Point(327, 128);
            this.tvFavorites.Name = "tvFavorites";
            this.tvFavorites.ShowGroups = false;
            this.tvFavorites.Size = new System.Drawing.Size(281, 244);
            this.tvFavorites.TabIndex = 8;
            this.tvFavorites.UseCompatibleStateImageBehavior = false;
            this.tvFavorites.View = System.Windows.Forms.View.Details;
            this.tvFavorites.VirtualMode = true;
            // 
            // olvColumn1
            // 
            this.olvColumn1.AspectName = "DisplayName";
            this.olvColumn1.FillsFreeSpace = true;

Во! Удалил компонент с формы, закинул заново и заработало! Никогда бы до этого не додумался.
Но теперь другая проблема. Как сделать, чтобы ширина столбца автоматически растягивалась до ширины TreeView, чтобы ее вручную не ресайзить? Установка значения в -1 не помогает.

Видимо это?

Во! А до удаления TreeView оно не работало.

Так, а если в дереве будут объекты, требующие Dispose(), как их удалить?

        private void Form1_FormClosed(object sender, FormClosedEventArgs e)
        {

        }

        private void tvFavorites_ItemsRemoving(object sender, BrightIdeasSoftware.ItemsRemovingEventArgs e)
        {

        }

Каждый раз вручную проходить по всем чилдренам и диспозить?
Или просто вызывать удаление каждого чилдрена, если он есть, и, таким образом, событие tvFavorites_ItemsRemoving рекурсивно придёт для всех чилдренов?

Оно наверно только для корня работает.

Так что для потомков можно сделать свое событие в своем объекте если очень надо, ну или при удалении проходить их.

Или просто в финалайзере вызывать Dispose если не надо гарантировано в момент удаления.

Кстати, попробовал удалить не корневой нод. Событие приходит, а из списка ничего не удаляется. Как тогда удалять?

Так а удаление как сделано? Надо как и добавление, с RefreshObject.

            tvFavorites.Roots = new List<MyData>() { new MyData() { DisplayName = "Избранное", Parent = null } };
            MyData favoritesRootNode = tvFavorites.Roots.Cast<MyData>().ToArray()[0];
            MyData d = new MyData(){ DisplayName = "ррр", Parent = favoritesRootNode };
            favoritesRootNode.Children.Add(d);
            d.Children.Add(new MyData() { DisplayName = "ABC", Parent = d });
            tvFavorites.RemoveObject(favoritesRootNode.Children[0]);
            tvFavorites.RefreshObject(favoritesRootNode);

Add/RemoveObject это для корней, тут надо из Children удалять.

            category.Items.RemoveAt(0);

            tvItems.RefreshObject(category);

Да, точно. Оно же само себя не удалит.

Тут еще вопрос назрел (наверное, последний).
А как получить MyData выделенного нода? Дерево ведь с нодами не связано. Если я правильно понял, TreeListView это ListBox на стеройдах и у него вообще нодов нету.

        private void tvFavorites_MouseDoubleClick(object sender, MouseEventArgs e)
        {
            MyData d = (sender as BrightIdeasSoftware.TreeListView).SelectedItem. ???? //что тут писать?
        }

В вашем примере используется какой-то TypedObjectListView, но там не понятно, что это и как работает. Это какой-то совсем не синглтон :grinning: