WinRT ListView UI虚拟化和DataTemplateSelector,具有大量模板(10-15)



我需要显示具有不同项目的ListView(总共10-15个项目类型)。为此,我使用DataTemplateSelector。但这会导致ListView在滚动过程中出现奇怪的行为:在某个时刻,它会跳到列表视图的顶部。我为UWP找到了这篇文章:https://msdn.microsoft.com/en-us/windows/uwp/debug-test-perf/optimize-gridview-and-listview.它说ItemTemplateSelector只支持5个DataTemplates

此外,项目模板选择器在评估特定容器是否可以用于当前数据项目时,只考虑五个可能的候选者。

我认为这就是原因。我试图减少DataTemplateSelector返回的DataTemplates的数量,它解决了这个问题:滚动按预期工作。但是,如何在不减少数据模板数量的情况下解决此问题?我知道我可以禁用虚拟化,但如果可能的话,我希望继续启用它。

对于UWP,可以选择使用ChoosingItemContainer事件,但它不适用于WinRT。

是否可以在不禁用WinRT中的UI虚拟化的情况下解决此问题?

这就是我最终在项目中所做的(我有一个无限滚动的列表视图)。基本上,我自己做了一部分虚拟化。

我完全删除了DataTemplateSelector。相反,我对所有项目使用一个模板:

<ListView  
    ...
    >
    <ListView.ItemTemplate>
        <DataTemplate>
            <messages:MyCustomContainer />
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>

其中MyCustomContainer是一个简单的UserControl:

<UserControl
    x:Class="MyCustomContainer"
    ...
    DataContextChanged="OnDataContextChanged"
    >
    <Grid x:Name="Container"/>
</UserControl>

我在MyCustomContainer:的代码背后实例化并选择合适的嵌套模板

void OnDataContextChanged(FrameworkElement sender, DataContextChangedEventArgs args)
{
    var context = DataContext as MyModelThatHelpsDecideOnAppropriateVisualTemplate;
    if (context == null) {
        // this means, item has been removed from the list and cached (we call this 'virtualization')
        Container.Children.Remove(CurrentTemplate);
        ReleaseTemplate(CurrentTemplate); // clear and cache our concrete template
        CurrentTemplate = null;
    } else {
        // this means, we need to get a concrete template
        // ... some logic to decide on the proper visual template type
        Type templateType = GetTemplateTypeForData(context);
        // ... some logic to get visual template from cache
        CurrentTemplate = GetTemplateFromCache(templateType);
        Container.Children.Add(CurrentTemplate);
    }     
}

从好的方面来看,这很好(对我来说很好,我有大约十几个项目模板)。

另一方面,通过这种方式,UI框架只虚拟化MyCustomContainer列表项,并且您必须自己缓存具体的视觉效果。在我的示例中,您必须将10-15个模板的实例存储在某个缓存中,并实现GetTemplateTypeForData()GetTemplateFromCache()ReleaseTemplate()。。。但这应该非常简单,我花了大约100行代码。

最新更新