Повторное использование содержимого вкладки с DataTemplate - PullRequest
0 голосов
/ 01 февраля 2019

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

Я устанавливаю содержимое вкладки с помощью DataTemplate.следующим образом:

<DataTemplate>
    <ScrollViewer Content="{Binding Content}" />
</DataTemplate>

Где Content - модель представления для представления, которое я хочу показать на вкладке.

В других местах я использую шаблоны данных для сопоставления каждой модели представления представлению, например

<DataTemplate DataType="{x:Type vm:MyViewModel1}">
    <ctl:CacheContentControl ContentType="{x:Type ctl:MyView1}" />
</DataTemplate>

<DataTemplate DataType="{x:Type vm:MyViewModel2}">
    <ctl:CacheContentControl ContentType="{x:Type ctl:MyView2}" />
</DataTemplate>

CacheContentControl - это оболочка для ContentControl, которую я использую для кэширования:

public class CacheContentControl : ContentControl
{
    private static Dictionary<Type, Control> cache = new Dictionary<Type, Control>();

    public CacheContentControl()
    {
        Unloaded += CacheContentControl_Unloaded;
    }

    private void CacheContentControl_Unloaded(object sender, RoutedEventArgs e)
    {
        Content = null;
    }

    private Type _contentType;
    public Type ContentType
    {
        get { return _contentType; }
        set
        {
            _contentType = value;
            Content = GetView(_contentType);  
        }
    }

    public Control GetView(Type type)
    {
        if (!cache.ContainsKey(type))
        {
            cache.Add(type, (Control)Activator.CreateInstance(type));
        }

        return cache[type];
    }
}

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

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

Я предполагаю, что это происходит, потому что я не могу показать тот же экземпляр элемента управления наодна и та же форма несколько раз, что имеет смысл.Я смог обойти это, передав событие IsVisibleChanged для моего CacheContentControl следующим образом:

    private void CacheContentControl_IsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
    {
        if (IsVisible && ContentType != null)
        {
            Control ctl = GetView(_contentType);
            ctl.DataContext = DataContext;
            Content = ctl;
        }
        else
        {
            Content = null;
        }
    }

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

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

1 Ответ

0 голосов
/ 06 февраля 2019

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

Обычный подход внутри DataTemplate с ключом по типу состоит не в использовании ContentControl, а просто в использовании UserControl в качестве шаблона.

 <DataTemplate x:Key=“MyViewmodelType”>
<MyViewControl />
</DataTemplate>

В TabControl будет ContentControl, для которого Content установлен в зависимости от того, какая ViewModel применима, и WPF автоматически отобразит его, используя указанный DataTemplate для этого типа, и установит DataContext.

Я создал массивные представления WPF, которые отображались с использованием DataTemplates согласно простому подходу, описанному выше, без каких-либо серьезных проблем с производительностью, и я думаю, что вы можете безопасно начать разработку, просто связав ContentControl.Content с вашим экземпляром ViewModel ипозволяя WPF обрабатывать рендеринг с использованием более простого подхода DataTemplate, описанного выше.

...