WPF — просмотр дерева и виртуализация ContentControl

#c# #wpf #treeview #contentcontrol

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

Вопрос:

У меня есть просмотр дерева с itemsource, содержащий элементы пользовательского класса TreeViewItem.

У меня есть свойство SelectedTreeviewItemViewModel типа TreeViewItem.

 public TreeviewItem SelectedTreeviewItemViewModel //with INPC
  

У меня есть элемент управления содержимым где-то еще в окне

         <ContentControl Content="{Binding SelectedTreeviewItemViewModel}" /> 
  

с таблицей данных следующим образом:

     <DataTemplate DataType="{x:Type TreeviewItem}">
        <uc:TreeviewCustomView />
    </DataTemplate>
  

Когда я нажимаю на элемент treeview, запускается событие SelectedItemChanged, и я устанавливаю SelectedTreeviewItemViewModel, которое заставляет contentcontrol обновлять его содержимое.

Логика в порядке, однако я заметил, что когда я нажимаю на новый элемент в treeview, некоторые данные обновляются, но я не перехожу в конструктор пользовательского элемента управления (uc: TreeviewCustomView).

Задействована ли какая-то виртуализация? Я предполагаю, что WPF кэширует datatemplate; могу ли я каким-либо образом заставить WPF воссоздавать пользовательский элемент управления с нуля (таким образом, переходя в конструктор) каждый раз, когда я нажимаю на элемент treeview?

Ответ №1:

Древовидные представления виртуализируются по умолчанию при использовании привязки. Если вы переключите режим на VirtualizingPanel.VirtualizationMode=»Standard», вместо «Recycling» должен быть вызван конструктор.

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

1. Проблема не находится в treeview. Я могу использовать режим виртуализации, но это не принесет мне никакой пользы: проблема находится в элементе управления контентом, который, похоже, кэширует храм данных.

Ответ №2:

Вот что помогло мне:

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

В моем xaml я начинаю с присвоения имени шаблону данных:

     <DataTemplate x:Key="TreeviewItemTemplate" DataType="{x:Type TreeviewItem}">
        <uc:TreeviewCustomView />
    </DataTemplate>
  

Затем я создаю селектор шаблонов следующим образом:

 public class TreeviewItemTemplateSelector : DataTemplateSelector
{
    public override DataTemplate SelectTemplate(object item, DependencyObject container)
    {
        if (item == null)
        {
            return null;
        }
        var declaredDataTemplate = ((FrameworkElement)container).FindResource("TreeviewItemTemplate") as DataTemplate;
        var wrappedDataTemplate = WrapDataTemplate(declaredDataTemplate );
        return wrappedDataTemplate;
    }

    private static DataTemplate WrapDataTemplate(DataTemplate declaredDataTemplate)
    {
        var frameworkElementFactory = new FrameworkElementFactory(typeof(ContentPresenter));
        frameworkElementFactory.SetValue(ContentPresenter.ContentTemplateProperty, declaredDataTemplate);
        var dataTemplate = new DataTemplate();
        dataTemplate.VisualTree = frameworkElementFactory;
        return dataTemplate;
    }
}
  

И, наконец, я использую селектор в своем элементе управления контентом:

 <ContentControl Content="{Binding SelectedTreeviewItemViewModel }"
                ContentTemplateSelector="{StaticResource TreeviewItemTemplateSelector }" />