背景: 私はアプリに取り組んでいます。ページの 1 つはニュース フィードです。ニュースのデータは動的です。複数のテキスト ブロックや多数の画像が含まれる場合があり、コンテンツに基づいてニュース項目ごとにレイアウトが計算されます。
ListBox/DataTemplate/Binding で動作させることはできない (方法がわからない) ため、低レベルのアプローチに進み、仮想化キャンバスを実装しようとしました: https://dl.dropbox.com/u/16063542/ MyVirtualizingPanel.cs
アイデアは簡単です:
含まれるすべてのアイテムは以下を実装します。
public interface 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 メソッドを実装します。
public void 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(セグメント セグメント、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(セグメント セグメント、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);
}
}
多かれ少なかれ、それは機能します。ただし、レイアウトが複雑になり、複数の画像が表示されるようになると、スクロールのパフォーマンスがやや低下します。それに加えて、時々レンダリング時に顕著な問題があります: 突然 (1 フレームの間) 要素の位置がずれて表示され、「まばたき」のように見えますが、それを説明する方法がわかりません。とにかく、私の質問: このアプローチには最初に欠陥がありますか? それとも、それを機能させるために努力し続けるべきですか?