在WPF DataGrid中进行延迟加载和分组

时间:2017-10-13 05:52:13

标签: wpf datagrid grouping lazy-loading

我需要在DataGrid中显示一个数据列表(100,000~500,000),其中有几列显示图像而不是简单数据。我必须使用“延迟加载”,因为无法一次加载所有图像。

此列表应支持过滤排序分组

我目前的实现是通过ScrollChanged事件触发“获取图像”(使用ScrollChangedEventArgs.VerticalOffset作为startIndex)。如果列表尚未分组,它可以正常工作。但是,如果我使用CollectionView对数据进行分组,当滚动条的垂直偏移不再被视为数据索引时,如何知道需要获取图像的正确数据项?

我正在考虑使用两个ViewModel的另一个解决方案。一个是普通的ViewModel,一个是GroupedViewMode。我可以在DataGrid中显示分组数据,如下所示:

public class GroupedData{

    public string ColumnName{get;set;}
    public bool Expanded{get;set;}
    public List<Data> List{get;set;}
}

然后,当滚动条值发生变化时,我可以以某种方式获取需要获取图像的数据。但是,这是另一个问题......如何在DataGrid

中绑定此数据格式

=========================

IsVirtualizingWhenGrouping很好,但它不能完全解决我的问题,我仍然需要首先加载内存中的所有数据。数据可能高达千兆字节,耗费内存。所以我目前的解决方案是加载所有数据,排除图像以支持排序,分组等,然后在需要时加载图像。

2 个答案:

答案 0 :(得分:0)

自.Net 4.5以来,Microsoft已添加IsVirtualizingWhenGrouping属性。如果您设置DataGrid的此属性,那么您不需要自己完成所有操作,因为DataGrid将仅加载可见数据/图像。

<DataGrid VirtualizingPanel.IsVirtualizingWhenGrouping="True">

答案 1 :(得分:0)

我认为您必须在viewmodel中延迟加载图像,因此只有在(虚拟化)UI首次请求时才会加载它。

如果您为源代码创建MemoryMappedFile并为每个数据条目*创建MemoryMappedViewStream,那么Data类可能如下所示:

class Data
{
    // Whatever size every data entry may have
    const int SizePerDataInFile = 100;
    // Offset of the image data within a single data entry
    const int ImageDataOffset = 40;
    // Size of the image data
    const int ImageDataLength = 60;

    public Data(MemoryMappedViewStream entriesFile)
    {
        _EntriesFile = entriesFile;
    }
    private MemoryMappedViewStream _EntriesFile;


    public int EntryIndex { get; set; }

    public string GroupableProperty { get; set; }


    public BitmapImage _Picture;
    public BitmapImage Picture
    {
        get
        {
            if (_Picture == null)
            {
                _EntriesFile.Seek(EntryIndex * SizePerDataInFile + ImageDataOffset, SeekOrigin.Begin);
                byte[] imageData = new byte[ImageDataLength];
                _EntriesFile.Read(imageData, 0, ImageDataLength);

                _Picture = new BitmapImage();
                using (var mem = new MemoryStream(imageData))
                {
                    mem.Position = 0;
                    _Picture.BeginInit();
                    _Picture.CreateOptions = BitmapCreateOptions.PreservePixelFormat;
                    _Picture.CacheOption = BitmapCacheOption.OnLoad;
                    _Picture.UriSource = null;
                    _Picture.StreamSource = mem;
                    _Picture.EndInit();
                }
                _Picture.Freeze();
            }
            return _Picture;
        }
    }
}

这意味着您初始化所有数据的“廉价”属性,它们将用于分组等。只有在通过从文件中读取相关数据块来访问图像时才会加载图像。

*即使我建议每个数据条目MemoryMappedViewStream,我也不确定 - 也许所有数据的共享视图流都足够了。