主题
虚拟化面板(VirtualizingPanel)
仅渲染可见区域的列表控件,适用于大数据量列表。通过模板和数据源绑定,自动创建/回收子控件。
定义位置:GameUI.Control.Primitive.VirtualizingPanel
继承链:VirtualizingPanel → PanelScrollable → Panel → Control
基本用法
csharp
// 创建垂直虚拟列表
var panel = VirtualizingExtensions.VirtualList(itemTemplate, itemSize: new SizeF(0, 40));
panel.Items(dataList);
panel.Parent = parentControl;构造
csharp
VirtualizingPanel();
VirtualizingPanel(IGameLink<GameDataControlVirtualizingPanel> link);数据绑定
ItemsSource
csharp
IEnumerable<object>? ItemsSource { get; set; }设置数据源后,调用 GenerateChildren() 触发虚拟化。子控件通过 Control.DataContext 获取绑定的数据项,Control.ItemIndex 获取索引。
模板
csharp
IGameLink<GameDataControl>? ItemTemplate { get; set; } // 单一模板
ItemTemplateSelector? ItemTemplateSelector { get; set; } // 按数据项选择模板
delegate IGameLink<GameDataControl>? ItemTemplateSelector(object item);属性
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
ItemSize | SizeF? | null | 固定项尺寸(提高性能) |
CacheLength | VirtualizationCacheLength | 视口外缓冲区大小 | |
CacheLengthUnit | VirtualizationCacheLengthUnit | Page | 缓冲区单位 |
ArrangeOnScroll | bool | false | 滚动时立即重排 |
IsVirtualizing | bool | 只读 | 是否正在虚拟化 |
滚动属性(继承自 PanelScrollable)
| 属性 | 类型 | 说明 |
|---|---|---|
ScrollOrientation | Orientation | 滚动方向 |
FlowOrientation | Orientation? | 子项排列方向 |
ScrollEnabled | bool | 是否允许滚动 |
ScrollBarValue | float | 滚动位置 |
ScrollBarSize | float | 滚动条大小 |
ScrollBarColor | ColorBrush | 滚动条颜色 |
方法
csharp
void GenerateChildren(); // 启动虚拟化
void InvalidateMeasure(); // 重新计算布局
void InvalidateArrange(); // 重新排列
void ClearCache(); // 清除回收池
Control? GetChildByItem(int itemIndex); // 按数据索引获取控件
bool BringItemIntoView(int itemIndex); // 滚动到指定项事件
csharp
// 子控件虚拟化/取消虚拟化时触发(可用于初始化/清理)
event EventHandler<ApplyControlTemplatePhaseEventArgs>? OnChildVirtualizationPhase;
// 滚动变化(继承自 PanelScrollable)
event EventHandler<ScrollChangedEventArgs>? OnScrollChanged;工厂方法
VirtualizingExtensions 提供快捷创建:
csharp
// 垂直列表
static VirtualizingPanel VirtualList(
IGameLink<GameDataControl> itemTemplate,
SizeF? itemSize = null,
float cachePages = 1.0f);
// 水平列表
static VirtualizingPanel VirtualHorizontalList(
IGameLink<GameDataControl> itemTemplate,
SizeF? itemSize = null,
float cachePages = 1.0f);
// 带模板选择器
static VirtualizingPanel VirtualListWithSelector(
ItemTemplateSelector selector,
Orientation orientation = Orientation.Vertical,
SizeF? itemSize = null,
float cachePages = 1.0f);流式配置
csharp
var panel = VirtualizingExtensions.VirtualList(template)
.ItemSize(0, 60)
.Cache(0.5f, 0.5f, VirtualizationCacheLengthUnit.Page)
.Items(dataList)
.ArrangeOnScroll(true);流式方法
csharp
static VirtualizingPanel Cache(this VirtualizingPanel panel,
float beforeViewport, float afterViewport,
VirtualizationCacheLengthUnit unit = Page);
static VirtualizingPanel ItemSize(this VirtualizingPanel panel, float width, float height);
static VirtualizingPanel ItemSize(this VirtualizingPanel panel, float size);
static VirtualizingPanel Template(this VirtualizingPanel panel, IGameLink<GameDataControl> template);
static VirtualizingPanel TemplateSelector(this VirtualizingPanel panel, ItemTemplateSelector selector);
static VirtualizingPanel Items<T>(this VirtualizingPanel panel, IEnumerable<T> items,
bool autoVirtualization = true);
static VirtualizingPanel ArrangeOnScroll(this VirtualizingPanel panel, bool enabled = true);子控件交互
VirtualizingPanel 没有内置选择/点击处理。通过子控件事件实现:
csharp
panel.OnChildVirtualizationPhase += (s, e) =>
{
var child = e.Control;
var data = child.DataContext; // 绑定的数据项
var index = child.ItemIndex; // 数据索引
child.Click(() =>
{
Game.Logger.LogInformation("点击了第 {Index} 项", index);
});
};回收机制
- 设置
ItemsSource+ItemTemplate(或ItemTemplateSelector) GenerateChildren()启动虚拟化- 滚动时,离开视口的控件进入
RecyclePool - 新进入视口的控件优先从回收池取出复用,减少实例化开销
BeforeViewportPlaceHolder/AfterViewportPlaceHolder占位撑开滚动区域
性能建议
- 设置固定
ItemSize避免逐项测量 CacheLength控制预渲染量,过大浪费内存,过小导致闪烁- 使用
ArrangeOnScroll(true)在快速滚动时更流畅
相关文档
- UI 布局指南 — 控件布局