【问题标题】:Lazy loading and grouping in WPF DataGridWPF DataGrid 中的延迟加载和分组
【发布时间】:2018-03-25 04:49:46
【问题描述】:

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

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

我目前的实现是通过ScrollChanged 事件触发“获取图像”(以ScrollChangedEventArgs.VerticalOffset 作为起始索引)。如果列表没有被分组,它工作正常。但是,如果我使用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不错,但不能完全解决我的问题,我还是需要先把内存中的数据全部加载进去。数据可能高达千兆字节,它会消耗内存。所以我目前的解决方案是加载所有排除图像的数据以支持排序、分组等,然后在需要时加载图像。

【问题讨论】:

  • 您的问题有很多问题。最明显的是这个:“但是,这是另一个问题……” 请不要将多个问题合二为一。相反,提出一个针对单个问题的问题。如果您有多个问题,请提出多个问题(最好不要一次全部提出,而是先从第一个开始,然后在问下一个问题之前尝试处理结果)
  • @grek40 很抱歉,我发布了所有内容。我是 WPF 的新手。我只是希望也许有人以前遇到过类似的情况并能给我一些提示......
  • @ASh UI 虚拟化可以部分解决我的问题,但不是全部。
  • 图片来自哪里?它们是存储在数据库中、其他地方还是从数据库值动态创建的?

标签: wpf datagrid grouping lazy-loading


【解决方案1】:

我认为您必须在视图模型中延迟加载图像,因此只有在(虚拟化)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,但我对此不太确定 - 也许所有数据的共享视图流就足够了。

【讨论】:

    【解决方案2】:

    从 .Net 4.5 开始,微软添加了IsVirtualizingWhenGrouping 属性。如果您设置了 DataGrid 的这个属性,那么您不需要自己做所有的事情,因为 DataGrid 将只加载可见的数据/图像。

    <DataGrid VirtualizingPanel.IsVirtualizingWhenGrouping="True">
    

    【讨论】:

    • 这是 UI 虚拟化,它仍然需要加载内存中的所有数据。我想做的是某种数据虚拟化。据我所知,目前还没有好的解决方案。
    猜你喜欢
    • 1970-01-01
    • 2019-02-01
    • 2012-02-29
    • 1970-01-01
    • 1970-01-01
    • 2011-03-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多