65.9K
CodeProject 正在变化。 阅读更多。
Home

WPF 虚拟化网格控件

starIconstarIconstarIconstarIconstarIcon

5.00/5 (13投票s)

2014年5月27日

CPOL

3分钟阅读

viewsIcon

45580

downloadIcon

1679

一个响应式二维电子表格式控件。

引言

最近,我发现自己一直在网上搜索一个高度灵活、虚拟化的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不能处理泛型类,所以您需要从DynamicGridControl 派生

public class DynamicGridSampleControl : DynamicGridControl<SampleGridItem, string, DateTime>
{ 

类型参数指定

  1. TDataSource:数据项的类型(稍后绑定到 DataSource 属性)。
  2. TRow:数据项的属性的类型,该属性包含行信息。
  3. 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 来更新可见单元格的内容。

© . All rights reserved.