【问题标题】:Random access data virtualization for ListView on Windows RuntimeWindows Runtime 上 ListView 的随机访问数据虚拟化
【发布时间】:2015-02-06 08:04:33
【问题描述】:

我正在实现一个可以轻松包含 10,000 张小图片的列表。实际用例是显示视频缩略图列表,因此您可以逐帧滚动视频。我在视频中每 2/3 秒将视频的缩略图放入列表中。我需要支持很长的视频(例如 1 小时视频)。

所以虚拟化选项:

http://msdn.microsoft.com/en-us/library/windows/apps/xaml/hh780657.aspx

我尝试了“增量数据虚拟化”,这对我来说消耗了太多内存,因为图像只能通过流引用,我最终会打开 10,000 个流。由于内存不足,这会导致 Windows Phone 应用程序崩溃。

现在我想尝试“随机访问数据虚拟化”。我看到了如何实现接口IObservableVector<object>, INotifyCollectionChanged(是的<object> b/c <T> 不起作用)。棘手的部分是我如何处理图像和加载图像。加载图像是一种异步方法。

此外,我相信这个解决方案应该有占位符,正如 MSFT 文档所说“这种类型的数据虚拟化的例子经常出现在照片查看应用程序中。而不是让用户等待下载相册中的所有照片,该应用程序显示占位符图像。当检索到每个图像时,应用程序会将该图像的占位符元素替换为实际照片的渲染。即使尚未下载和显示所有图像,用户仍然可以平移并与集合交互。”

查看占位符的 MSFT 示例 - 使用“ContainerContentChanging”似乎是一条重要路径。我在这里猜测有一种方法可以在此事件中处理图像,并开始加载图像。 https://code.msdn.microsoft.com/windowsapps/ListViewSimple-d5fc27dd

归结为一个问题 - 可以在哪里处理图像流并开始为随机访问虚拟化列表加载图像?这是照片应用程序中非常常见的场景并且在 iOS 中非常容易做到,但似乎还没有人在 Windows 运行时做到这一点。

【问题讨论】:

    标签: c# windows-runtime windows-phone-8.1 windows-8.1


    【解决方案1】:

    必须适配VirtualizingCollection的实现,请查看以下文章http://www.codeproject.com/Articles/34405/WPF-Data-Virtualization

    我使用适用于 Windows Phone 8.1 运行时应用程序的 VirtualizingCollection 编写了一个示例应用程序。

    public class ThumbnailItem
    {
        public Uri ImageUri { get; set; }
    }
    

    稍后编写 ThumbnailItem 提供程序。

    public class ThumbnailProvider : IItemsProvider<ThumbnailItem>
    {
        private readonly int _itemsCount;
    
        public ThumbnailProvider(int itemsCount)
        {
            _itemsCount = itemsCount;
        }
    
        public int FetchCount()
        {
            return _itemsCount;
        }
    
        public IList<ThumbnailItem> FetchRange(int startIndex, int count)
        {
            var items = new List<ThumbnailItem>();
            while (count-- > 0)
            {
                items.Add(new ThumbnailItem()
                {
                    ImageUri = new Uri("ms-appx:///Assets/Square71x71Logo.scale-240.png")
                });
            }
            return items;
        }
    }
    

    然后,在您的 ViewModel 中,您必须创建一个 IList 属性并使用 VirtualizingCollection 的实现来设置该值。我建议你使用 AsyncVirtualizingCollection。

    Items = new AsyncVirtualizingCollection<ThumbnailItem>(new ThumbnailProvider(1000000), 100);
    

    最后,在视图上,您​​必须使用 ViewModel 的实例设置 DataContext 对象,您的 ListView 应该类似于:

    <ListView   
        ItemsSource="{Binding Items,Mode=OneWay}"
        VirtualizingStackPanel.VirtualizationMode="Recycling">
    <ListView.ItemsPanel>
        <ItemsPanelTemplate>
            <WrapGrid Orientation="Horizontal"/>
        </ItemsPanelTemplate>
    </ListView.ItemsPanel>
    
    <ListView.ItemTemplate>
        <DataTemplate>
            <Grid Margin="0 0 20 20">
                <Image Source="{Binding ImageUri,Mode=OneTime}"
                       Width="72" Height="72"/>
            </Grid>
        </DataTemplate>
    </ListView.ItemTemplate>
    

    当然,提供者的逻辑必须根据你的要求改变,我写的代码只是一个示例。

    如果对你有帮助,请标记为答案。

    最好的问候, 拒绝

    编辑 朋友@Quincy,我贴了一个简单的例子,你可以适应它。也许对于您的应用程序,ThumbnailItem 类将包含指示 IsolateStorageFile 文件名的 Filename 属性。在这种情况下,您必须使用转换器创建一个 Binding,因此您需要实现一个 IValueConverter 对象以使用 IsolateStorageFile 创建一个 BitmapImage 实例。

    BitmapImage image = new BitmapImage(); image.SetSource(sourceFile); 返回图片;

    关于图片关闭,VirtualizingCollection定义了一个pagesize,默认为100。您的 IsolateStorageFiles 将用于在您的 IValueConverter 对象中创建 BitmapImage 一次。之后VirtualizingCollection会删除不使用的旧页面(不显示,检查VirtualizingCollection实现),最后GC将关闭并处理BitmapImage。

    移植 VirtualizingCollection 很简单,我记得我刚刚对 AsyncVirtualizingCollection 类进行了更改。我的解决方案很简单:

    将 ThreadPool.QueueUserWorkItem 替换为 ThreadPool.RunAsync。

    将 Trace 替换为 Debug(只是调试消息,不是很重要)。

    使用以下方法替换 SynchronizationContext 方法调用:

    (对于 Windows 手机应用)CoreApplication.MainView.CoreWindow.Dispatcher。

    (对于 Windows 应用)CoreApplication.MainView.Dispatcher。

    希望对你有帮助。

    【讨论】:

    • 在此您无需自己加载图像,这是我需要做的。您只是使用 URI。我需要打开一个流并最终关闭它
    • 这些代码不是都依赖于 WPF 吗? AsyncVirtualizingCollection 在 winrt 中不可用
    • 我的重点是我肯定需要自己打开一个流来下载图像。虚拟化并没有为我关闭它。我在测试中内存不足,我继续看到内存增加。我正在使用 mediacomposition api 从视频中获取缩略图。这是一个 async/await 方法。
    • 我有一个封闭的解决方案,可以释放内存,但滚动列表时出现缓慢的 UI 问题。由于保密协议,我认为我不能发布我的代码。我会检查一下
    猜你喜欢
    • 2021-06-15
    • 1970-01-01
    • 1970-01-01
    • 2016-02-10
    • 1970-01-01
    • 1970-01-01
    • 2020-07-17
    • 1970-01-01
    • 2018-12-30
    相关资源
    最近更新 更多