Производный от HierarchicalDataTemplate - PullRequest
0 голосов
/ 09 сентября 2018

Я бы хотел выполнить отложенную загрузку 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.

...