WPF 虚拟化网格控件
一个响应式二维电子表格式控件。
引言
最近,我发现自己一直在网上搜索一个高度灵活、虚拟化的WPF网格控件,以便以类似时间表的方式向用户展示大量数据,用户应该能够选择一个项目继续。
我没有找到任何合适的控件,并且在尝试了虚拟化堆栈面板后,它无法满足我对灵活性和响应性的需求,我决定自己实现一个可重用的网格。
特点
- 高度响应(长时间的任务异步执行,加载时显示进度条)。
- 高度可定制(可以使用DataTemplate来样式化网格线、标题和内容)。
- 快速(在2秒内加载具有整数列/标题信息的100万个数据项)。
- 利用多个CPU核心(使用TPL)。
- 自动将一维源数组转换为二维网格(通过使用两个源项目的属性来计算x/y位置)。
示例
上面显示的控件的数据源是 IEnumerable<SampleGridItem>
。 SampleGridItem
看起来像这样
public class SampleGridItem
{
public string ProductName { get; set; }
public DateTime ProductionDate { get; set; }
public int ProductionCount { get; set; }
}
使用控件 - 逐步指南
1. 包含您可以在此页面上下载的项目
下载,解压缩并将其添加为项目引用。
2. 创建一个新类并从 DynamicGridControl<> 派生。
因为WPF不能处理泛型类,所以您需要从DynamicGridContro
派生l
public class DynamicGridSampleControl : DynamicGridControl<SampleGridItem, string, DateTime>
{
类型参数指定
TDataSource
:数据项的类型(稍后绑定到DataSource
属性)。TRow
:数据项的属性的类型,该属性包含行信息。TCol
:数据项的属性的类型,该属性包含列信息。
3. 创建默认构造函数
要告诉控件哪些数据源的属性包含行/标题信息,您需要分配前两个委托 (columnSelector
/ rowSelector
)。
第三个委托控制当多个数据项与同一行/列组合相关时会发生什么。
public DynamicGridSampleControl()
: base(
item => item.ProductName,
item => item.ProductionDate,
items => new SampleGridItem()
{
ProductName = items.First().ProductName,
ProductionDate = items.First().ProductionDate,
ProductionCount = items.Sum(item => item.ProductionCount)
})
4. 排序?
如果要对行/列标题进行排序,请分配一个 RowComparer
/ ColumnComparer
。
由于行/列 ID 是通用的并且可以是任何 CLR 类型,因此您需要添加有关如何比较项目的逻辑。 大多数时候,您可以使用类型的 CompareTo()
方法
this.ColumnComparer = (a, b) => a.CompareTo(b);
5. 创建一个静态构造函数来创建默认样式
告诉WPF在创建网格时使用哪个样式
static DynamicGridSampleControl()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(DynamicGridSampleControl), new FrameworkPropertyMetadata(typeof(DynamicGridSampleControl)));
}
6. 从示例项目中复制默认样式
复制默认样式 (DynamicGridSampleControlDefaultStyle.xaml) 并调整命名空间。
大多数情况下,没有必要修改控件模板,以下情况除外
- 您想更改网格线的样式(如果想使每隔一行/列例如粉红色,它们已经提供了一个
IsOdd
-Property)。 - 你知道你在做什么 :-)
7. 创建您的控件并将您的数据绑定到 DataSource - 属性
重要提示:将您的控件包装在 ScrollViewer 中,并将 CanContentScroll
设置为 True
。
否则您将无法滚动。
<ScrollViewer CanContentScroll="True"
HorizontalScrollBarVisibility="Auto"
VerticalScrollBarVisibility="Auto">
<local:DynamicGridSampleControl ItemWidth="100" ItemHeight="30" DataSource="{Binding Data}" />
</ScrollViewer>
8. 设置样式!
您可以
- 通过设置
DataItemTemplate
/DataItemTemplateSelector
来设置单元格样式。 - 通过设置
HeaderTemplate
/HeaderTemplateSelector
来设置标题样式。 - 通过设置
WaitLayerTemplate
来设置等待层样式。
工作原理
很简单。
如果分配 DataSource
,则会构建一个不同的列/行表(异步和 TPL)。
然后构建一个二维 itemsCache
以便在滚动时快速查找(异步)。
为了显示数据,对于每个可见单元格,都会创建一个可绑定的 ViewModel (DynamicGridDataItem
等),它将其当前单元格的内容包装在其 Content
属性中(非常像 ItemContainerGenerator 的回收行为)。
如果滚动或调整窗口大小,则通过简单地访问 itemsCache
来更新可见单元格的内容。