如何推迟绑定请求,直到项目在屏幕上可见?

时间:2014-04-15 11:10:14

标签: xaml windows-phone-8

我注意到ListBox es和LongListSelector s,项目绑定属性请求被推迟到滚动为止。
是否可以对ScrollViewer中的自定义定位项执行相同的操作,以便项目在向其滚动之前不会对其绑定属性值发出任何请求?是否有任何简单的设置可以自动实现?
如果没有,那么最简单的方法是什么呢?

1 个答案:

答案 0 :(得分:0)

它叫做Lazy Load  这里有一个懒惰列表的例子:

public class LazyCollection<T> : IList<T>, IList, INotifyCollectionChanged, INotifyPropertyChanged
{
    private const int LOAD_THRESHOLD = 3;

    private ObservableCollection<T> _innerCollection;

    public LazyCollection(Func<int, IEnumerable<T>> fetch)
        : this(fetch, null)
    { }

    public LazyCollection(Func<int, IEnumerable<T>> fetch, IEnumerable<T> items)
    {
        _fetch = fetch;
        _innerCollection = new ObservableCollection<T>(items ?? new T[0]);
        this.AttachEvents();
        this.HasMoreItems = true;
    }

    private void AttachEvents()
    {
        _innerCollection.CollectionChanged += (s, e) => OnCollectionChanged(e);
        ((INotifyPropertyChanged)_innerCollection).PropertyChanged += (s, e) => OnPropertyChanged(e);
    }

    #region INotifyPropertyChanged
    public event PropertyChangedEventHandler PropertyChanged;
    protected virtual void OnPropertyChanged(PropertyChangedEventArgs e)
    {
        if (this.PropertyChanged != null)
            this.PropertyChanged(this, e);
    }
    #endregion

    #region INotifyCollectionChanged
    public event NotifyCollectionChangedEventHandler CollectionChanged;
    protected virtual void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
    {
        if (this.CollectionChanged != null)
            this.CollectionChanged(this, e);
    }
    #endregion

    #region IList<T>
    public int IndexOf(T item)
    {
        return _innerCollection.IndexOf(item);
    }

    public void Insert(int index, T item)
    {
        _innerCollection.Insert(index, item);
    }

    public void RemoveAt(int index)
    {
        _innerCollection.RemoveAt(index);
    }

    public T this[int index]
    {
        get
        {
            Debug.WriteLine("LazyCollection - Reading item {0}", index);
            return _innerCollection[index];
        }
        set { _innerCollection[index] = value; }
    }

    public void Add(T item)
    {
        _innerCollection.Add(item);
    }

    public void Clear()
    {
        _innerCollection.Clear();
    }

    public bool Contains(T item)
    {
        return _innerCollection.Contains(item);
    }

    public void CopyTo(T[] array, int arrayIndex)
    {
        _innerCollection.CopyTo(array, arrayIndex);
    }

    public int Count
    {
        get { return _innerCollection.Count; }
    }

    public bool IsReadOnly
    {
        get { return ((IList<T>)_innerCollection).IsReadOnly; }
    }

    public bool Remove(T item)
    {
        return _innerCollection.Remove(item);
    }

    public IEnumerator<T> GetEnumerator()
    {
        Debug.WriteLine("LazyCollection - GetEnumerator");
        return _innerCollection.GetEnumerator();
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        Debug.WriteLine("LazyCollection - GetEnumerator explicit");
        return ((IEnumerable)_innerCollection).GetEnumerator();
    }
    #endregion

    #region IList
    int IList.Add(object value)
    {
        return ((IList)_innerCollection).Add(value);
    }

    bool IList.Contains(object value)
    {
        return ((IList)_innerCollection).Contains(value);
    }

    int IList.IndexOf(object value)
    {
        return ((IList)_innerCollection).IndexOf(value);
    }

    void IList.Insert(int index, object value)
    {
        ((IList)_innerCollection).Insert(index, value);
    }

    bool IList.IsFixedSize
    {
        get { return ((IList)_innerCollection).IsFixedSize; }
    }

    bool IList.IsReadOnly
    {
        get { return ((IList)_innerCollection).IsReadOnly; }
    }

    void IList.Remove(object value)
    {
        ((IList)_innerCollection).Remove(value);
    }

    object IList.this[int index]
    {
        get
        {
            if (index > this.Count - LOAD_THRESHOLD)
            {
                this.TryLoadMoreItems();
            }

            Debug.WriteLine("LazyCollection - Reading item {0} IList", index);
            return ((IList)_innerCollection)[index];
        }
        set { ((IList)_innerCollection)[index] = value; }
    }

    void ICollection.CopyTo(Array array, int index)
    {
        ((IList)_innerCollection).CopyTo(array, index);
    }

    bool ICollection.IsSynchronized
    {
        get { return ((IList)_innerCollection).IsSynchronized; }
    }

    object ICollection.SyncRoot
    {
        get { return ((IList)_innerCollection).SyncRoot; }
    }
    #endregion

    public T[] GetLoadedItems()
    {
        return _innerCollection.ToArray();
    }

    public void ResetLoadedItems(IEnumerable<T> list)
    {
        _innerCollection.Clear();
        foreach (var i in list)
            _innerCollection.Add(i);
        this.HasMoreItems = true;
    }

    public bool HasMoreItems { get; set; }
    private bool _isLoading = false;
    private Func<int, IEnumerable<T>> _fetch;

    private async Task TryLoadMoreItems()
    {
        if (_isLoading || !this.HasMoreItems)
            return;

        try
        {
            _isLoading = true;

            Debug.WriteLine("LazyCollection - Loading more items skip {0}", this.Count);
            List<T> items = _fetch != null ? (_fetch(Count)).ToList() : new List<T>();

            if (items.Count == 0)
            {
                Debug.WriteLine("LazyCollection - No items returned, Loading disabled", this.Count);
                this.HasMoreItems = false;
            }

            items.ForEach(x => _innerCollection.Add(x));

            Debug.WriteLine("LazyCollection - Items added. Total count: {0}", this.Count);
        }
        finally
        {
            _isLoading = false;
        }


    }
}
public class SearchResults : LazyCollection<Verse>
{
    public SearchResults()
        : base(count => GetSearchResult(), GetSearchResult())
    {

    }

    public static int _index = 0;
    public static string CurrentSearch = "";
    public static List<Verse> AllVerses = new List<Verse>();
    private static List<Verse> GetSearchResult()
    {
        List<Verse> results = new List<Verse>();
        string lower = CurrentSearch.ToLower();
        bool resultsChanged = false;
        for (int index = _index; index < AllVerses.Count; index++)
        {
            Verse verse = AllVerses[index];
            if (verse.Content.ToLower().Contains(lower) || verse.Header.ToLower().Contains(lower))
            {
                results.Add(verse);
                resultsChanged = true;
            }
            if ((index >= (AllVerses.Count / 200) + _index || index + 1 == AllVerses.Count) && resultsChanged && (results.Count > 10 || AllVerses.Count == index + 1))
            {
                _index = index + 1;
                return results;
            }
        }
        return results;
    }
}