Производный от HierarchicalDataTemplate

Я хотел бы выполнить отложенную загрузку TreeViewItem в WPF. Я уже знаю общий ответ - добавить несколько «виртуальных» элементов в ItemsSource и в событии Expanded для обмена этим виртуальным элементом с реальным списком.

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

Изменение свойства HasItems на самом деле не работает, поскольку свойство HasItems глубоко закодировано в TreeViewItem. Поэтому я решил добавить LazyItemsSource к TreeViewItem (DynamicTreeViewItem), и если кто-то расширяет узел, LazyItemsSource назначается ItemsSource.

Проблема в том, что мне нужно управлять иерархией через HierarchicalDataTemplate. Вместо назначения ItemsSource в шаблоне я хотел назначить LazyItemsSource, но почему-то это невозможно. Отображаемая ошибка:

ошибка MC4104: свойство «LazyItemsSource» не может быть установлено в качестве элемента свойства в шаблоне. В качестве элементов свойств можно использовать только триггеры и раскадровки. Строка 10 Позиция 79.

Но я понятия не имею, почему компилятор жалуется на это. Вот исходный код:

using System.Collections;
using System.Windows;
using System.Windows.Controls;

namespace WpfApp8
{
    public class DynamicTreeView : TreeView
    {
        protected override DependencyObject GetContainerForItemOverride()
        {
            return new DynamicTreeViewItem();
        }
    }

    public class DynamicTreeViewItem : TreeViewItem
    {
        public static readonly DependencyProperty LazyItemsSourceProperty
                   = DependencyProperty.Register("LazyItemsSource", typeof(IEnumerable), typeof(ItemsControl),
                                                 new FrameworkPropertyMetadata((IEnumerable)null,
                                                                               new PropertyChangedCallback(OnLazyItemsSourceChanged)));
        public bool IsSourceAssigned
        {
            get;
            private set;
        } = false;

        public IEnumerable LazyItemsSource
        {
            get => (IEnumerable)GetValue(LazyItemsSourceProperty);
            set => SetValue(LazyItemsSourceProperty, value);
        }

        private static void OnLazyItemsSourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
        }

        protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e)
        {
            if (e.Property == IsExpandedProperty)
            {
                if (!IsSourceAssigned)
                {
                    SetValue(ItemsSourceProperty, new int[] { 1, 2, 3, 4, 5 });
                    IsSourceAssigned = true;
                }
            }
            base.OnPropertyChanged(e);
        }

        private readonly static IEnumerable LazySource = new ArrayList(new[] { new object() });

        public DynamicTreeViewItem()
        {
            Loaded += DynamicTreeViewItem_Loaded;
        }

        private void DynamicTreeViewItem_Loaded(object sender, RoutedEventArgs e)
        {
            SetValue(ItemsSourceProperty, LazySource);
        }
    }

    public class DynamicHierarchicalDataTemplate : HierarchicalDataTemplate
    {
        public IEnumerable LazyItemsSource
        {
            get;
            set;
        }
    }
}

а также XAML:

<Window x:Class = "WpfApp8.MainWindow"
        xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d = "http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc = "http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local = "clr-namespace:WpfApp8"
        mc:Ignorable = "d"
        Title = "MainWindow" Height = "450" Width = "800">
    <Window.Resources>
        <local:DynamicHierarchicalDataTemplate DataType = "{x:Type local:Node}" LazyItemsSource = "{Binding Items}">
            <TextBlock Text = "{Binding}"/>
        </local:DynamicHierarchicalDataTemplate>
    </Window.Resources>
    <Grid>
        <local:DynamicTreeView ItemsSource = "{Binding Tree.Items}"/>
    </Grid>
</Window>

В настоящее время я могу это сделать с помощью этого решения, но я не понял, что заставляет компилятор жаловаться:

<HierarchicalDataTemplate DataType = "{x:Type local:Node}">
    <HierarchicalDataTemplate.ItemContainerStyle>
        <Style TargetType = "{x:Type local:DynamicTreeViewItem}">
            <Setter Property = "LazyItemsSource" Value = "{Binding Items}"/>
        </Style>
    </HierarchicalDataTemplate.ItemContainerStyle>
    <TextBlock Text = "{Binding}"/>
</HierarchicalDataTemplate>

У меня создалось впечатление, что это должно быть довольно просто, но я не уверен, каковы внутренние детали DataTemplate.

typeof(ItemsControl) как третий параметр DependencyProperty.Register определенно неверен. Это должен быть typeof(DynamicTreeViewItem). Кроме того, когда вы переопределяете GetContainerForItemOverride, вы также должны переопределять IsItemItsOwnContainer.
Clemens 09.09.2018 23:05

Это определенно хороший аргумент @Clemens. Я скопировал это из исходного кода и не проверял. Другой момент с IsitemsItsOwnContainer верен, но в моем случае, возможно, в этом нет необходимости. Исходный код из TreeView делает следующее: возвращаемый элемент - TreeViewItem. Поскольку мой элемент является производным от TreeViewItem, это должно быть проблемой. Тем не менее, он не работает и по-прежнему показывает ту же ошибку.

msedi 10.09.2018 06:03

@msedi, LazyItemsSource не является DP, поэтому он не поддерживает привязку LazyItemsSource = "{Binding Items}"

ASh 10.09.2018 10:05

@Ash: Я так понимаю, ты так думаешь. В реализации нового DynamicTreeViewItem это DependencyProperty, если вы проверите код. В HierarchicalDataTemplate, если вы проверяете исходный источник, даже ItemsSource является не DependencyProperty, а простым свойством.

msedi 10.09.2018 11:33

если вы проверите исходный источник, ItemsSource имеет тип BindingBase, который совместим с Binding

ASh 10.09.2018 11:35

Ах. Да, вы правы. Я уже изменил это на то, как он используется в HierarchicalDataTemplate, и сделал LazyItemsSource также BindingBase. Но он по-прежнему не работает и дает ту же ошибку.

msedi 10.09.2018 13:14
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
6
69
0

Другие вопросы по теме