我最终根据 Simon Ferques 的指导方针做了一个 POC。我在这里添加代码以供将来参考。
public class VirtualizaingVector<T> : ObservableObject, IObservableVector<object>
{
public event VectorChangedEventHandler<object> VectorChanged;
private Dictionary<int, T> _items;
private int _count;
private bool _countCalculated;
private IItemSupplier<T> _itemSuplier;
public VirtualizaingVector(IItemSupplier<T> itemSupplier)
{
_itemSuplier = itemSupplier;
_items = new Dictionary<int, T>();
}
#region Notifications
private void _notifyVectorChanged(VectorChangedEventArgs args)
{
if (VectorChanged != null)
{
VectorChanged(this, args);
}
}
private void _notifyReset()
{
var args = new VectorChangedEventArgs(CollectionChange.Reset, 0);
_notifyVectorChanged(args);
}
private void _notifyReplace(int index)
{
var args = new VectorChangedEventArgs(CollectionChange.ItemChanged, (uint)index);
_notifyVectorChanged(args);
}
#endregion
#region Private
private void _calculateCount()
{
_itemSuplier.GetCount().ContinueWith(task =>
{
lock (this)
{
_count = task.Result;
_countCalculated = true;
}
NotifyPropertyChanged(() => this.Count);
_notifyReset();
}, TaskScheduler.FromCurrentSynchronizationContext());
}
private void _startRefreshItemAsync(T item)
{
var t = new Task(() =>
{
_itemSuplier.RefreshItem(item);
});
t.Start(TaskScheduler.FromCurrentSynchronizationContext());
}
private void _startCreateItemAsync(int index)
{
var t = new Task<T>(() =>
{
return _itemSuplier.CreateItem(index);
});
t.ContinueWith(task =>
{
lock (this)
{
_items[index] = task.Result;
}
_notifyReplace(index);
}, TaskScheduler.FromCurrentSynchronizationContext());
t.Start(TaskScheduler.FromCurrentSynchronizationContext());
}
#endregion
public object this[int index]
{
get
{
T item = default(T);
bool hasItem;
lock (this)
{
hasItem = _items.ContainsKey(index);
if (hasItem) item = _items[index];
}
if (hasItem)
{
_startRefreshItemAsync(item);
}
else
{
_startCreateItemAsync(index);
}
return item;
}
set
{
}
}
public int Count
{
get
{
var res = 0;
lock (this)
{
if (_countCalculated)
{
return res = _count;
}
else
{
_calculateCount();
}
}
return res;
}
}
#region Implemenetation of other IObservableVector<object> interface - not relevant
...
#endregion
}
public interface IItemSupplier<T>
{
Task<int> GetCount();
T CreateItem(int index);
void RefreshItem(T item);
}
几点注意事项:
- 虽然向量是 T 的可枚举,但它实现的接口是 IObservableVector。原因是由于某种原因 WinRt 项目控件不听任何
IObservableVector<T>
,只为IObservableVector<object>
。悲伤但真实...
- 虚拟化 vercor 将项目供应商作为参数并使用它来查询虚拟列表中的项目数量以及项目本身。它还允许项目供应商在从缓存中删除后再次访问项目时刷新项目
- 此类是为特定场景编写的,其中内存不是问题,但时间是问题。它确实保留了一个已经创建的缓存项目列表,但它会延迟它们的创建,直到它们第一次被访问。