У меня есть класс EntityDisplay, который содержит 2 свойства:
public sealed class EntityDisplayObject
{
public ICollection Collection { get; private set; }
public string CollectionName { get; private set; }
public EntityDisplayObject(ICollection collection)
{
this.Collection = collection;
this.CollectionName = $"{this.Collection.GetType().Name [{this.Collection.Count}]";
}
}
Иногда Коллекция будет List<int>, а иногда List<List<int>.
В настоящее время я работаю со списком, но не могу найти способ сделать это для вложенных списков.
Это мой xaml на данный момент:
<Grid x:Uid = "Grid_4">
<TreeView x:Uid = "TreeView_2"
Background = "Transparent"
BorderThickness = "0"
Padding = "0">
<TreeViewItem x:Uid = "TreeViewItem_1"
Header = "{Binding CollectionName}">
<ListBox x:Uid = "ListBox_2" MouseDoubleClick = "TreeViewItem_MouseDoubleClick"
ItemsSource = "{Binding Collection}"
Background = "Transparent"
BorderThickness = "0">
</ListBox>
</TreeViewItem>
</TreeView>
</Grid>
Простой список, работающий с xaml
Для вложенных списков я получаю заголовок древовидного представления и возможность расширения, но вместо того, чтобы показывать список на первом снимке экрана, он дает мне (Коллекция). На данный момент вложенный список
Сосредоточьтесь на структуре Class_ParentChild_Model, вы ее получите, или опубликуйте свой class code для simple List<string>
Итак... вам нужно иерархическое древовидное представление? например. stackoverflow.com/questions/1912481
@RandRandom спасибо, что помогло! В конце мне нужно было извлечь все элементы внутри коллекции и добавить их в новый список (это делается внутри некоторых проверок if, чтобы убедиться, что в коллекции есть элементы внутри, а затем, если какой-либо из этих элементов также является коллекцией , он повторит процесс. Наконец, в xaml внутри древовидного представления я привязываю элемент управления itemsControl к этому новому списку.





Если вы не хотите преобразовывать структуру данных, вы можете определить DataTemplateSelector, который определяет фактический тип элементов EntityDisplayObject.Collection и выбирает соответствующий DataTemplate:
class MyDataTemplateSelector : DataTemplateSelector
{
public DataTemplate DefaultTemplate { get; set; }
public DataTemplate NestedListTemplate { get; set; }
public override DataTemplate SelectTemplate(object item, DependencyObject container)
=> item is IEnumerable
? this.NestedListTemplate
: this.DefaultTemplate;
}
<Window xmlns:sys = "clr-namespace:System;assembly=mscorlib"
xmlns:collections = "clr-namespace:System.Collections;assembly=System.Runtime">
<TreeView x:Uid = "TreeView_2"
Background = "Transparent"
BorderThickness = "0"
Padding = "0">
<TreeViewItem x:Uid = "TreeViewItem_1"
Header = "{Binding CollectionName}">
<ListBox x:Uid = "ListBox_2"
ItemsSource = "{Binding Collection}"
Background = "Transparent"
BorderThickness = "0">
<ListBox.ItemTemplateSelector>
<local:MyDataTemplateSelector>
<local:MyDataTemplateSelector.DefaultTemplate>
<DataTemplate DataType = "{x:Type sys:Int32}">
<TextBlock Text = "{Binding}" />
</DataTemplate>
</local:MyDataTemplateSelector.DefaultTemplate>
<local:MyDataTemplateSelector.NestedListTemplate>
<DataTemplate DataType = "{x:Type collections:IList}">
<HeaderedItemsControl ItemsSource = "{Binding}" />
</DataTemplate>
</local:MyDataTemplateSelector.NestedListTemplate>
</local:MyDataTemplateSelector>
</ListBox.ItemTemplateSelector>
</ListBox>
</TreeViewItem>
</TreeView>
</Window>
Однако вложенный список — плохой выбор для реализации древовидной структуры данных в объектно-ориентированном программировании. Это внесет некоторые странности.
Я рекомендую преобразовать вашу структуру данных, поскольку это значительно упростит работу с вашими данными и представлениями. Поэтому вместо List<List<int>> вы можете использовать List<EntityDisplayObject>. По соображениям производительности в примере List<T> заменяется на ObservableCollection<T>:
EntityDisplayObject.cs
class EntityDisplayObject : INotifyPropertyChanged
{
public ObservableCOllection<EntityDisplayObject> Children { get; }
public object Value { get; }
public EntityDisplay(object value) : this(Enumerable.Empty<EntityDisplayObject>(), value)
{
}
public EntityDisplay(IEnumerable<EntityDisplayObject> children, object value)
{
this.Children = new ObservableCollection<EntityDisplayObject>(children);
this.Value = value;
}
}
MainWindow.xaml.cs
partial class MainWindow : Window
{
public ObservableCollection<EntityDisplayObject> TreeData { get; }
public MainWindow()
{
InitializeComponent();
this.Loaded += OnLoaded;
this.TreeData = new ObservableCollection<EntityDisplayObject>();
}
private void OnLoaded(object sender, RoutedEventArgs e)
{
var rootItem = new EntityDisplayObject("Root");
// Create a child without nested children.
// Children are a simple list of int values.
var intChildren = Enumerable.Range(1, 10);
var simpleChild = new EntityDisplayObject(intChildren, "Simple child");
rootItem.Children.Add(simpleChild);
// Create a child with nested children.
// Each child contains a list of int values
IEnumerable<EntityDisplayObject> nestedChildren = Enumerable
.Range(11, 10)
.Select(value =>
{
var children = Enumerable.Range(100 * value, 10)
.Select(childValue => new EntityDisplayObject(childValue));
var child = new EntityDisplayObject(children, value);
});
var nestedChildrenParent = new EntityDisplayObject(nestedChildren, "Nested child #1");
rootItem.Add(nestedChildrenParent);
// Create another child with nested children.
// Each child contains a list of int values
nestedChildren = Enumerable
.Range(21, 10)
.Select(value =>
{
var children = Enumerable.Range(200 * value, 10)
.Select(childValue => new EntityDisplayObject(childValue));
var child = new EntityDisplayObject(children, value);
});
nestedChildrenParent = new EntityDisplayObject(nestedChildren, "Nested child #1");
rootItem.Add(nestedChildrenParent);
this.TreeData.Add(rootItem);
}
}
MainWindow.xaml
<Window x:Name = "VisualRoot">
<TreeView ItemsSource = {Binding ElementName=VisualRoot, Path=TreeData}">
<TreeView.ItemTemplate>
<HierarchicalDataTemplate DataType = "{x:Type EntityDisplayObject}"
ItemsSource = "{Binding Children}">
<TextBlock Text = "{Binding Value}" />
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
</Window>
Разве this.Children = children; не должно быть this.Children = new(children);?
For performance reasons the example replaces List<T> with ObservableCollection<T>: - есть ли у вас какая-либо документация, подтверждающая эту проблему с производительностью?
@КостасК. Да, точно. Я написал этот код здесь, в текстовом редакторе, без проверки типа. Очевидно, я был немного неряшлив. Спасибо что подметил это.
@RandRandom Нет ни одной статьи Microsoft. Это мои знания, основанные на нескольких статьях Microsoft и обзорах исходного кода. Пожалуйста, прочитайте: Привязка к списку приводит к утечке памяти для краткого обзора. Еще один момент, который не упоминается в этом сообщении, заключается в том, что использование реализации INotifyCollectionChanged позволяет обновлять экземпляр исходной коллекции вместо его замены для обновления представления, что позволяет избежать полного прохода рендеринга ItemsControl. что может быть очень дорого (обычно это приводит к зависанию пользовательского интерфейса).
Спасибо всем за помощь. В конце концов, этот код выполнил свою работу. Что мне нужно было сделать, так это для каждой коллекции получить элементы и поместить их в новое свойство List, и если какие-либо элементы также являются коллекциями, сделать то же самое с ними, что даст каждому объекту список дочерних элементов (если они Коллекция).
foreach (var child in collection)
{
if (child is ICollection childCollection && childCollection.Count > 0)
{
var childObject = new EntityDisplayObject(childCollection);
this.ChildCollection.Add(childObject);
}
А вот как выглядит xaml, позволяющий отображать что-то вроде этого
Item 1
-Item 2
-Item 3
-Item 4
-Item 5
-Item 6
-Item 7
<TreeView x:Uid = "TreeView_2"
Background = "Transparent"
BorderThickness = "0"
Padding = "0"
ScrollViewer.HorizontalScrollBarVisibility = "Disabled">
<TreeViewItem x:Uid = "TreeViewItem_1"
Header = "{Binding CollectionName}">
<ItemsControl ItemsSource = "{Binding ChildCollection}"
ItemTemplateSelector = "{StaticResource EntityInspectorDataTemplateSelector}"
Background = "Transparent"
BorderThickness = "0">
</ItemsControl>
</TreeViewItem>
</TreeView>
Смотрите этот ответ stackoverflow.com/a/78556341/3392605