powered by simpleCommunicator - 2.0.51     © 2025 Programmizd 02
Форумы / WPF, Silverlight [игнор отключен] [закрыт для гостей] / Универсальная модель представления для узла TreeView
25 сообщений из 54, страница 1 из 3
Универсальная модель представления для узла TreeView
    #38631565
user7320
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
В этой статье у автора есть модели представления для узлов дерева, но такое ощущение, что на каждый раз приходится делать новую модель представления. Потому что презентационные свойства (свойства, относящиеся к виду узла, развёрнут ли он и т. п.) у него перемешаны со свойтсвами данных (т. е. относящимися к модели).

Я выделил только презентационную часть и у меня получилась универсальная модель узла:

Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
public class Noded_VM
{
    // Fields
    
    private Noded_VM _parent;
    private Model _current;
    private readonly ObservableCollection<Noded_VM> _children;

    private bool _isExpanded;
    private bool _isSelected;


    // Presentation properties.

    public Noded_VM Parent
    {
        get { return _parent; }
        set { _parent = value; }
    }

    public ObservableCollection<Noded_VM> Children
    {
        get { return _children; }
    }

    /// <summary>
    /// Gets or sets whether the TreeViewItem associated with this object is expanded.
    /// </summary>
    public bool IsExpanded
    {
        get { return _isExpanded; }
        set
        {
            SetProperty(() => _isExpanded, v => _isExpanded = v, value);

            // Expand all the way up to the root.
            if (_isExpanded && _parent != null)
                _parent.IsExpanded = true;
        }
    }

    /// <summary>
    /// Gets or sets whether the TreeViewItem associated with this object is selected.
    /// </summary>
    public bool IsSelected
    {
        get { return _isSelected; }
        set { SetProperty(() => _isSelected, v => _isSelected = v, value); }
    }


    // Constructors.
    
    /// <summary>
    /// To create root of the tree.
    /// </summary>
    /// <param name="current"></param>
    public Noded_VM(Model current)
        : this(current, null)
    { }

    /// <summary>
    /// To create nodes and leafs of the tree.
    /// </summary>
    /// <param name="current"></param>
    /// <param name="parent"></param>
    private Noded_VM(Model current, Noded_VM parent)
    {
        _parent = parent;
        _current = current;
        _children = new ObservableCollection<Noded_VM>(
            _current.Children
            .Select(child => new Noded_VM(child, this))
            .ToList());
    }
}



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

Как сделать эту мою базовую модель реюзабельной с требованиями:

- вместо Model должен быть любой тип модели;
- этот тип модели должен иметь свойство Children, возвращающее IEnumerable<Model>?


И более общий вопрос - кто как делал у себя модели представлений для отображения в TreeView? У вас есть какая-то универсальная модель, или каждый раз заново делаете?
...
Рейтинг: 0 / 0
Универсальная модель представления для узла TreeView
    #38631567
user7320
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
В свойствао IsExpanded и IsSelected не обращайте внимания на строчки вида

Код: c#
1.
SetProperty(() => _isExpanded, v => _isExpanded = v, value)



На самом деле там обычный сеттер вида _isExpanded = value.
...
Рейтинг: 0 / 0
Универсальная модель представления для узла TreeView
    #38631568
Lelouch
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
user7320,

Например, так:
1) Ввести для модели такой интерфейс:
Код: c#
1.
2.
3.
4.
public interface ITreeModel
{
	IEnumerable<T> Children { get; }
}


2) Вот так модифицировать класс Noded_VM:
Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
public class Noded_VM<T> where T : ITreeModel
{
    // Fields
    
    private Noded_VM _parent;
    private T _current;
    private readonly ObservableCollection<Noded_VM<T>> _children;

    // ...

    private Noded_VM(T current, Noded_VM<T> parent)
    {
        _parent = parent;
        _current = current;
        _children = new ObservableCollection<Noded_VM<T>>(
            _current.Children
            .Select(child => new Noded_VM<T>(child, this))
            .ToList());
    }

}
...
Рейтинг: 0 / 0
Универсальная модель представления для узла TreeView
    #38631570
Lelouch
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Noded_VM<T> _parent *
...
Рейтинг: 0 / 0
Универсальная модель представления для узла TreeView
    #38631573
Lelouch
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
user7320,

если конкретный тип поля _current не важен, то можно обойтись и без генерика, просто подставив в ваш код вместо Model ITreeModel
...
Рейтинг: 0 / 0
Универсальная модель представления для узла TreeView
    #38631576
Lelouch
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Еще 1 фикс:
Код: c#
1.
2.
3.
4.
public interface ITreeModel
{
	IEnumerable<ITreeModel> Children { get; }
}
...
Рейтинг: 0 / 0
Универсальная модель представления для узла TreeView
    #38631590
user7320
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Я тоже раньше к такой реализации приходил. Но запутался в деталях. В частности, и у меня тогда, и по вашей реализации сейчас (включая все ваши последние фиксы) я получал ошибку на строке

Код: c#
1.
.Select(child => new Noded_VM<T>(child, this))



Ошибка такая

Argument 1: cannot convert from 'ITreeNodeModel' to 'T'
...
Рейтинг: 0 / 0
Универсальная модель представления для узла TreeView
    #38631591
user7320
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
user7320Argument 1: cannot convert from 'ITreeNodeModel' to 'T'
Это тот же ваш интерфейс ITreeModel, просто я его по-другому назвал.
...
Рейтинг: 0 / 0
Универсальная модель представления для узла TreeView
    #38631592
user7320
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
user7320Argument 1: cannot convert from 'ITreeNodeModel' to 'T'
Это тот же ваш интерфейс ITreeModel, просто я его по-другому назвал.
...
Рейтинг: 0 / 0
Универсальная модель представления для узла TreeView
    #38631596
user7320
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Ну и далее те же проблемы, что были и у меня. Беру объект, который выполняет интерфейс ITreeNodeModel:

Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
public class Quest : ITreeNodeModel
{
    protected List<Quest> _children;
    public List<Quest> Children
    {
        get
        {
            if (_children == null)
                _children = new List<Quest>();

            return _children;
        }

        set { _children = value; }
    }
}



Ошибка такая

'Quest' does not implement interface member 'ITreeNodeModel.Children'.
'Quest.Children' cannot implement 'ITreeNodeModel.Children' because it does not have the matching return type of 'System.Collections.Generic.IEnumerable<ITreeNodeModel>'.

Я не понимаю, почему я не реализовал интерфейс - ведь List реализует IEnumerable.
...
Рейтинг: 0 / 0
Универсальная модель представления для узла TreeView
    #38631597
user7320
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Вот класс, расширяющий класс Noded_VM

Код: c#
1.
2.
3.
4.
5.
6.
public class NodedQuest_VM : Noded_VM
{
	private NodedQuest_VM(Quest current)
		: base(current)
	{ }
}



Ошибка на строчке base(current)

авторArgument 1: cannot convert from 'Quest' to 'ITreeNodeModel'
...
Рейтинг: 0 / 0
Универсальная модель представления для узла TreeView
    #38631598
user7320
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
user7320Ошибка на строчке base(current)

авторArgument 1: cannot convert from 'Quest' to 'ITreeNodeModel'
Тоже не понятно, почему нильзя привести, ведь Quest наследуется от ITreeNodeModel.
...
Рейтинг: 0 / 0
Универсальная модель представления для узла TreeView
    #38632066
Lelouch
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ведь List реализует IEnumerable. - и что? Он требует именно IEnumerable
...
Рейтинг: 0 / 0
Универсальная модель представления для узла TreeView
    #38632197
user7320
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Lelouchведь List реализует IEnumerable. - и что? Он требует именно IEnumerable
Он не только требует IEnumerable, но и ITreeNodeModel вместо типа, его реализуюего. Т. е. не только нельзя, чтобы Children возвращал это

List<Quest>

но и это

List<ITreeNodeModel>

и это

IEnumerable<Quest>


А как же приведение типов? Такое ощущение, что приведение типов работает в runtime, но не в designtime.
...
Рейтинг: 0 / 0
Универсальная модель представления для узла TreeView
    #38632198
user7320
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
user7320Lelouchведь List реализует IEnumerable. - и что? Он требует именно IEnumerable
Он не только требует IEnumerable, но и ITreeNodeModel вместо типа, его реализуюего. Т. е. не только нельзя, чтобы Children возвращал это

List<Quest>

но и это

List<ITreeNodeModel>

и это

IEnumerable<Quest>


А как же приведение типов? Такое ощущение, что приведение типов работает в runtime, но не в designtime.
Потому что внутри свойства Children я могу вернуть List<Quest>:

return List<Quest>

и всё будет нормально.
...
Рейтинг: 0 / 0
Универсальная модель представления для узла TreeView
    #38632201
user7320
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
А ещё заметил такое ограничение, что если я наследую

public class NodedQuest_VM : Noded_VM

в таком дизайне Noded_VM, как у меня , нельзя будет в XAML привязать ни одного свойства из NodedQuest_VM, если шаблон данных работает со свойством Children типа Noded_VM.

Можно как-то обойти это, чтобы Children родительского класса возвращал коллекцию объектов типа потомкового класса? Пока думаю снова с параметром типов, но боюсь, что слишком при этом всё усложнится. Щас попробую...
...
Рейтинг: 0 / 0
Универсальная модель представления для узла TreeView
    #38632205
user7320
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Пока сделал вот так, но пишет ошибку в строчке, что я обозначил

Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
public class Noded_VM<T> : ModeledBase_VM
    where T : Noded_VM<T>
{
    // Fields
    
    private T _parent;
    private ITreeNodeModel _current;
    private readonly ObservableCollection<T> _children;

    
    // Properties

    public T Parent
    {
        get { return _parent; }
        set { _parent = value; }
    }

    public ObservableCollection<T> Children
    {
        get { return _children; }
    }


    // Constructors

    /// <summary>
    /// To create root of the tree.
    /// </summary>
    public Noded_VM(ITreeNodeModel current)
        : this(current, null)
    { }

    /// <summary>
    /// To create nodes and leafs of the tree.
    /// </summary>
    private Noded_VM(ITreeNodeModel current, T parent)
        : base(current)
    {
        _parent = parent;
        _current = current;
        _children = new ObservableCollection<T>(
            _current.Children
            .Select(child => new T(child, this)) // ОШИБКА!   
                                                 // Cannot create an instance of the variable type 'T' 
                                                 // because it does not have the new() constraint
            .ToList());
    }
}



Если добавить new():

Код: c#
1.
where T : Noded_VM<T>, new()



то получаю в этой же строчке следующую ошибку

'T': cannot provide arguments when creating an instance of a variable type
...
Рейтинг: 0 / 0
Универсальная модель представления для узла TreeView
    #38632207
user7320
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Что-то как-то заморочено с этим тривью. Неужели никто не сделал универсальный контейнер для treeview node? Чтобы можно было любой тип в этот контейнер помещать и получать функциональность узла в дереве.
...
Рейтинг: 0 / 0
Универсальная модель представления для узла TreeView
    #38632210
user7320
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Если кому интересно, я тут создал такой же вопрос.
...
Рейтинг: 0 / 0
Универсальная модель представления для узла TreeView
    #38632215
user7320
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Пока только вот что придумал: надо в эту универсальную модель представления для узла добавлять всякие свойства для кастомизации. Например, DisplayName для отображения названия узла в дереве. Если чего посложнее надо - тоже добавить эти сложные свойства в эту универсальную модель.

Получается, что эта универсальная модель раздуется из-за этих расширений до невозможности.

А я хочу получать функциональность не таким раздуванием, а наследованием или ещё каким простым способом. Так, чтобы каждый кирпичик этих функциональностей содержал в себе только свою функциональность, а не кучу кода поддержки расширений.
...
Рейтинг: 0 / 0
Универсальная модель представления для узла TreeView
    #38632216
user7320
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
авторНапример, DisplayName для отображения названия узла в дереве. Если чего посложнее надо - тоже добавить эти сложные свойства в эту универсальную модель.
Я имед ввиду, а что, если я хочу не просто название в узле отображать, а некую сложную конструкцию? Придётся городить дополнительное свойство для отображения этой сложной конструкции...
...
Рейтинг: 0 / 0
Универсальная модель представления для узла TreeView
    #38632219
user7320
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
А, щас ещё раз взглянул на пример Джоша Смита . Во втором варианте, где у него города, штаты и прочее в дереве, у него как раз и есть базовая модель представления. Моя ошибка в том, что я сделал загрузку детей в этой же базовой модели, а он сделал метод загрузки виртуальным и предоставил потомковым моделям самим определять, как будут загружаться дети. Это позволяет отказаться от интерфейса со свойством, реализующим загрузку детей. Но, с другой стороны, это заставляет потомковые модели представления быть толще, чем они могли бы быть.

Вобщем, у Джоша Смита подход лучше. Его и буду использовать. Мой вариант настолько универсальный, что его реализация будет либо невозможной, либо чрезмерно громоздкой - всё из-за загрузки детей.
...
Рейтинг: 0 / 0
Универсальная модель представления для узла TreeView
    #38632228
Фотография Алексей К
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Есть универсальный родной TreeViewItem, как часть родной content model WPF. Накой лепить ещё одну универсальную абстракцию? Бинди его на конкретную ViewModel и радуйся жизни.
...
Рейтинг: 0 / 0
Универсальная модель представления для узла TreeView
    #38632230
Фотография Алексей К
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
user7320Вобщем, у Джоша Смита подход лучше. Его и буду использовать. Мой вариант настолько универсальный, что его реализация будет либо невозможной, либо чрезмерно громоздкой - всё из-за загрузки детей.У Джоша Смита подход так себе. Для загрузки детей дерева нужен аналог Lazy<T> с реализацией INotifyPropertyChanged. Вот моя асинхронная реализация.
...
Рейтинг: 0 / 0
Универсальная модель представления для узла TreeView
    #38632233
user7320
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Алексей Кuser7320Вобщем, у Джоша Смита подход лучше. Его и буду использовать. Мой вариант настолько универсальный, что его реализация будет либо невозможной, либо чрезмерно громоздкой - всё из-за загрузки детей.У Джоша Смита подход так себе. Для загрузки детей дерева нужен аналог Lazy<T> с реализацией INotifyPropertyChanged. Вот моя асинхронная реализация.
У Джоша ленивая загрузка. Я только с твоим async не понял, как она реализуется. Через другой поток?

А если асинк не нужен, то всё нормально?
...
Рейтинг: 0 / 0
25 сообщений из 54, страница 1 из 3
Форумы / WPF, Silverlight [игнор отключен] [закрыт для гостей] / Универсальная модель представления для узла TreeView
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]