背景:我正在开发应用程序。其中一页是新闻提要。新闻中的数据是动态的:它可能包含多个文本块、许多图像,并且根据内容为每个新闻项计算布局。
由于不可能(我不知道如何)使其与 ListBox/DataTemplate/Binding 一起使用,我采用较低级别的方法并尝试实现虚拟化画布: https ://dl.dropbox.com/u/16063542/ MyVirtualizingPanel.cs
想法很简单:
每个包含的项目都实现:
公共接口 IVirtualizable { void ChangeState(VirtualizableState newState);
VirtualizableState CurrentState { get; }
double FixedHeight { get; }
FrameworkElement View { get; }
Thickness Margin { get; }
}
-panel 应放入 ScrollViewer 并初始化:
public void InitializeWithScrollViewer(ScrollViewer _scrollViewer)
{
_listScrollViewer = _scrollViewer;
EnsureBoundToScrollViewer();
}
protected void EnsureBoundToScrollViewer()
{
Binding binding = new Binding();
binding.Source = _listScrollViewer;
binding.Path = new PropertyPath("VerticalOffset");
binding.Mode = BindingMode.OneWay;
this.SetBinding(ListVerticalOffsetProperty, binding);
}
Panel 实现 AddItems 方法:
公共无效AddItems(IEnumerable _itemsToBeAdded){
double topMargin = 0;
foreach (var itemToBeAdded in _itemsToBeAdded)
{
itemToBeAdded.View.Margin = new Thickness(0, itemToBeAdded.Margin.Top + topMargin, 0, 0);
_virtualizableItems.Add(itemToBeAdded);
topMargin += itemHeightIncludingMargin;
}
Height = topMargin;
}
然后根据滚动位置的变化加载和卸载项目:
private void LoadItemsInSegment(Segment segment, VirtualizableState desiredState) { for (int i = segment.LowerBound; i <= segment.UpperBound; i++) { var item = _virtualizableItems[i];
item.ChangeState(desiredState);
if (!Children.Contains(item.View))
{
Children.Add(item.View);
}
}
}
private void LoadItemsInSegment(Segment segment, VirtualizableState desiredState) { for (int i = segment.LowerBound; i <= segment.UpperBound; i++) { var item = _virtualizableItems[i];
item.ChangeState(desiredState);
if (!Children.Contains(item.View))
{
Children.Add(item.View);
}
}
}
private void UnloadItemsInSegment(Segment segment)
{
for (int i = segment.LowerBound; i <= segment.UpperBound; i++)
{
var item = _virtualizableItems[i];
Children.Remove(item.View);
item.ChangeState(VirtualizableState.Unloaded);
}
}
或多或少,它有效。但是,随着布局变得更加复杂并获得多个图像,滚动性能变得有些差。除此之外,在渲染时有时会出现明显的问题:突然(一帧)元素出现错位,看起来像“眨眼”,不知道如何解释。无论如何,我的问题是:这种方法最初是否有缺陷?还是我应该继续努力让它发挥作用?