使用DataTemplate重用选项卡内容

时间:2019-02-01 11:08:53

标签: c# wpf mvvm datatemplate

我有一个选项卡控件,其中在运行时创建选项卡。选项卡的内容将是几个用户控件之一,每个用户控件都包含数百个其他控件。由于创建这些用户控件需要很长时间,因此我试图找到一种重用它们的方法,而不是为每个选项卡创建一个新实例。

我正在使用DataTemplate设置标签页内容,如下所示:

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

“内容”是我要在标签中显示的视图的视图模型。

在其他地方,我使用数据模板将每个视图模型映射到一个视图,例如

<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在创建新实例之前先检查缓存以查看其是否可以重用控件。

这适用于创建的任何新选项卡。第一个选项卡的速度很慢,因为它需要创建初始控件,但是使用相同控件的所有后续选项卡几乎都会立即加载。我遇到的问题是,当我单击返回上一个选项卡时,该控件不再出现,并且该选项卡为空白。

我想这是因为我无法多次以相同的形式显示相同的控件实例,这是有道理的。通过将CacheContentControl的IsVisibleChanged事件处理如下,可以解决此问题:

    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 :(得分:0)

我不确定您是否需要去缓存用户控件,因为WPF在很大程度上为您做到了。

按类型键入键的DataTemplate内部的通常方法是不使用ContentControl,而只是使用UserControl作为模板。

data

TabControl将具有一个ContentControl,其Content设置为适用的ViewModel,WPF将使用该类型的指定DataTemplate自动呈现它并设置DataContext。

我已经按照上面概述的简单方法构建了使用DataTemplates渲染的大规模WPF视图,而没有遇到任何严重的性能问题,我认为您可以通过将ContentControl.Content绑定到ViewModel实例并让WPF处理来安全地开始开发使用上面较简单的DataTemplate方法进行渲染。