我需要在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
很好,但它不能完全解决我的问题,我仍然需要首先加载内存中的所有数据。数据可能高达千兆字节,耗费内存。所以我目前的解决方案是加载所有数据,排除图像以支持排序,分组等,然后在需要时加载图像。
答案 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
,我也不确定 - 也许所有数据的共享视图流都足够了。