// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) // This code is distributed under the GNU LGPL (for details please see \doc\license.txt) using System; using System.Collections.Generic; using System.Windows.Controls; using ILSpy.Debugger.Services; namespace ILSpy.Debugger.Tooltips { /// /// ItemsControl wrapper that takes VirtualizingIEnumerable as source, /// and adds additional items from the source to underlying ItemsControl when scrolled to bottom. /// public class LazyItemsControl { private ItemsControl itemsControl; private int initialItemsCount; /// /// Creates new instance of LazyItemsControl. /// /// ItemsControl to wrap and add items to it when scrolled to bottom. /// Number of items to be initially displayed in wrapped ItemsControl. public LazyItemsControl(ItemsControl wrappedItemsControl, int initialItemsCount) { if (wrappedItemsControl == null) throw new ArgumentNullException("wrappedItemsControl"); this.initialItemsCount = initialItemsCount; this.itemsControl = wrappedItemsControl; this.itemsControl.AddHandler(ScrollViewer.ScrollChangedEvent, new ScrollChangedEventHandler(handleScroll)); } private ScrollViewer scrollViewerCached; public ScrollViewer ScrollViewer { get { if (this.scrollViewerCached == null) this.scrollViewerCached = this.itemsControl.GetScrollViewer(); return this.scrollViewerCached; } } public bool IsScrolledToStart { get { if (ScrollViewer == null) // Visual tree not initialized yet return false; return ScrollViewer.VerticalOffset == 0; } } public bool IsScrolledToEnd { get { if (itemsSourceTotalCount == null) { // not scrolled to end of IEnumerable yet return false; } // already scrolled to end of IEnumerable int totalItems = itemsSourceTotalCount.Value; return (ScrollViewer.VerticalOffset >= totalItems - ScrollViewer.ViewportHeight); } } private int? itemsSourceTotalCount = null; /// Items count of underlying IEnumerable. Null until scrolled to the end of IEnumerable. public int? ItemsSourceTotalCount { get { return this.itemsSourceTotalCount; } } private VirtualizingIEnumerable itemsSource; /// The collection that underlying ItemsControl sees. public VirtualizingIEnumerable ItemsSource { get { return itemsSource; } set { this.itemsSource = value; addNextItems(this.itemsSource, initialItemsCount); this.itemsControl.ItemsSource = value; } } private void addNextItems(VirtualizingIEnumerable sourceToAdd, int nItems) { sourceToAdd.AddNextItems(nItems); if (!sourceToAdd.HasNext) { // all items from IEnumerable have been added this.itemsSourceTotalCount = sourceToAdd.Count; } } private void handleScroll(object sender, ScrollChangedEventArgs e) { if (e.VerticalChange > 0) { // scrolled to bottom if (e.VerticalOffset >= this.itemsSource.Count - e.ViewportHeight) { addNextItems(this.itemsSource, (int)e.VerticalChange); } } } } }