(WPF) Как настроить просмотр дерева с помощью is-a, а не has-a

#c# #wpf #mvvm #treeview

#c# #wpf #mvvm #просмотр дерева

Вопрос:

Из того, что я видел, TreeViews обычно ожидают, что модели будут использовать отношения have has-a, где родительский узел имеет ссылки на все его дочерние элементы. Пример: ExampleModel имеет коллекцию ExampleChildModel . В представлении дерева узлы ExampleChildModel отображаются как дочерние узлы ExampleModel. В моем случае мне нужно создать иерархию, определяемую свойством ExampleModel, а ExampleChildModel отсутствует.

Чтобы быть немного более конкретным, проблема, с которой я сталкиваюсь, заключается в следующем: мне нужно создать что-то, что отображает коллекцию элементов. Я думаю, что просмотр дерева — это правильный путь, но, возможно, я ошибаюсь. Каждый элемент имеет свойство группировки строк, свойство string DisplayName и свойство int Ordinality (а также некоторые другие свойства, которые не имеют отношения к этой проблеме):

 public class AModelWithACollection
{
    private ObservableCollection<StrippedDownModel> _collection;
    public ObservableCollection<StrippedDownModel> Collection
    {
        get => _collection;
        set => SetProperty(ref _collection, value);
    }

    //Lots of other properties that don't need to be shown in the TreeView
}

public class StrippedDownModel
{
    private string _grouping;
    public string Grouping
    {
        get => _grouping;
        set => SetProperty(ref _grouping, value);
    }

    private string _displayName;
    public string DisplayName
    {
        get => _displayName;
        set => SetProperty(ref _displayName, value);
    }

    private int _ordinality;
    public int Ordinality
    {
        get => _oridnality;
        set => SetProperty(ref _ordinality, value);
    }

    //Lots of other properties that don't need to be shown in the TreeView
}
 

Часть xaml, вероятно, будет выглядеть примерно так:

 <TreeView ItemsSource="{Binding ElementName=Root, Path=InstanceOfAModelWithACollection.Collection}">
    <TreeView.Resources>
        <!-- Not really what the DataTemplates here would look like -->
    </TreeView.Resources>
</TreeView>
 

Если бы у меня была коллекция из 5 объектов StrippedDownModel, и для 3 из них была установлена группировка «Группа 1», а для двух была установлена группировка «Группа 2», я бы ожидал дерево с 2 узлами с именами «Группа 1» и «Группа 2» с 3 и 2 дочерними элементами соответственно. Я бы также хотел, чтобы дочерние узлы упорядочивались по свойству Ordinality:

 Group 1
    Object 1
    Object 2
    Object 3

Group 2
    Object 4
    Object 5
 

Как мне это создать? Все примеры, которые я видел до сих пор, используют отношение has-a, которое я описал изначально.

Одна из моих мыслей заключалась в том, чтобы преобразовать StrippedDownModel во что-то, что использовало отношение has-a. Пример: создайте NewParentModel и NewChildModel и запустите AModelWithACollection.Сбор с помощью некоторого преобразования, которое создало бы экземпляры этих новых моделей, а затем привязало бы к ним. Мне нужно было бы придумать какой-то способ, чтобы изменения в этой преобразованной коллекции также отражались в исходной коллекции, поскольку эта исходная модель будет использоваться для создания dto, который отправляется на серверную часть для записи в базу данных.

Я бы предпочел способ просто привязки к AModelWithACollection.Тем не менее, мне не пришлось бы беспокоиться о преобразованиях и синхронизации двух моделей.

РЕДАКТИРОВАТЬ: для тех, кто сталкивается с той же проблемой: предложение, опубликованное @RolandJS, работает хорошо. Однако я не был поклонником заголовков групп, вызывающих некоторый когнитивный диссонанс с заголовками DataGrid. В итоге я изменил свою модель, чтобы она была больше похожа на стандартную модель, которую будет использовать TreeView. Теперь у него есть-a, поэтому у него есть коллекция коллекций StrippedDownModels, где родительскими коллекциями являются группы.

Комментарии:

1. Возможно, вы ищете сетку данных с сортировкой и группировкой. Смотрите Этот документ: docs.microsoft.com/en-us/dotnet/desktop/wpf/controls /…

2. @RolandJS На первый взгляд это кажется намного лучше. Я попробую это сделать. Спасибо за совет.