Windows运行时上ListView的随机访问数据虚拟化

时间:2014-12-08 16:00:41

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

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

虚拟化选择:

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

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

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

此外,我相信这个解决方案应该像MSFT doc所说的那样拥有占位符&#34;这种类型的数据虚拟化的一个例子经常出现在照片查看应用程序中。该应用程序显示占位符图像,而不是让用户等待下载相册中的所有照片。在检索每个图像时,应用程序会使用实际照片的渲染替换该图像的占位符元素。即使没有下载和显示所有图像,用户仍然可以平移并与集合进行交互。&#34;

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

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

1 个答案:

答案 0 :(得分:0)

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

我使用适用于Windows Phone 8.1 Runtime App的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(的资源文件);   返回图片;

关于图像关闭,VirtualizingCollection默认定义了一个pagesize,100。您的IsolateStorageFiles将使用一次在IValueConverter对象中创建BitmapImage。稍后,VirtualizingCollection将删除未使用的旧页面(未显示,请检查VirtualizingCollection实现),最后GC将关闭并配置BitmapImage。

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

将ThreadPool.QueueUserWorkItem替换为ThreadPool.RunAsync。

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

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

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

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

我希望它可以帮到你。