WPF Virtualizing Panel
来源:互联网 发布:淘宝买csgo怎么下载 编辑:程序博客网 时间:2024/06/02 03:42
都是国外的
VirtualizingWrapPanel:
public class VirtualizingWrapPanel : VirtualizingPanel, IScrollInfo{ #region Fields UIElementCollection _children; ItemsControl _itemsControl; IItemContainerGenerator _generator; private Point _offset = new Point(0, 0); private Size _extent = new Size(0, 0); private Size _viewport = new Size(0, 0); private int firstIndex = 0; private Size childSize; private Size _pixelMeasuredViewport = new Size(0, 0); Dictionary<UIElement, Rect> _realizedChildLayout = new Dictionary<UIElement, Rect>(); WrapPanelAbstraction _abstractPanel; #endregion #region Properties private Size ChildSlotSize { get { return new Size(ItemWidth, ItemHeight); } } #endregion #region Dependency Properties [TypeConverter(typeof(LengthConverter))] public double ItemHeight { get { return (double)base.GetValue(ItemHeightProperty); } set { base.SetValue(ItemHeightProperty, value); } } [TypeConverter(typeof(LengthConverter))] public double ItemWidth { get { return (double)base.GetValue(ItemWidthProperty); } set { base.SetValue(ItemWidthProperty, value); } } public Orientation Orientation { get { return (Orientation)GetValue(OrientationProperty); } set { SetValue(OrientationProperty, value); } } public static readonly DependencyProperty ItemHeightProperty = DependencyProperty.Register("ItemHeight", typeof(double), typeof(VirtualizingWrapPanel), new FrameworkPropertyMetadata(double.PositiveInfinity)); public static readonly DependencyProperty ItemWidthProperty = DependencyProperty.Register("ItemWidth", typeof(double), typeof(VirtualizingWrapPanel), new FrameworkPropertyMetadata(double.PositiveInfinity)); public static readonly DependencyProperty OrientationProperty = StackPanel.OrientationProperty.AddOwner(typeof(VirtualizingWrapPanel), new FrameworkPropertyMetadata(Orientation.Horizontal)); #endregion #region Methods public void SetFirstRowViewItemIndex(int index) { SetVerticalOffset((index) / Math.Floor((_viewport.Width) / childSize.Width)); SetHorizontalOffset((index) / Math.Floor((_viewport.Height) / childSize.Height)); } private void Resizing(object sender, EventArgs e) { if (_viewport.Width != 0) { int firstIndexCache = firstIndex; _abstractPanel = null; MeasureOverride(_viewport); SetFirstRowViewItemIndex(firstIndex); firstIndex = firstIndexCache; } } public int GetFirstVisibleSection() { int section; var maxSection = _abstractPanel.Max(x => x.Section); if (Orientation == Orientation.Horizontal) { section = (int)_offset.Y; } else { section = (int)_offset.X; } if (section > maxSection) section = maxSection; return section; } public int GetFirstVisibleIndex() { int section = GetFirstVisibleSection(); var item = _abstractPanel.Where(x => x.Section == section).FirstOrDefault(); if (item != null) return item._index; return 0; } private void CleanUpItems(int minDesiredGenerated, int maxDesiredGenerated) { for (int i = _children.Count - 1; i >= 0; i--) { GeneratorPosition childGeneratorPos = new GeneratorPosition(i, 0); int itemIndex = _generator.IndexFromGeneratorPosition(childGeneratorPos); if (itemIndex < minDesiredGenerated || itemIndex > maxDesiredGenerated) { _generator.Remove(childGeneratorPos, 1); RemoveInternalChildRange(i, 1); } } } private void ComputeExtentAndViewport(Size pixelMeasuredViewportSize, int visibleSections) { if (Orientation == Orientation.Horizontal) { _viewport.Height = visibleSections; _viewport.Width = pixelMeasuredViewportSize.Width; } else { _viewport.Width = visibleSections; _viewport.Height = pixelMeasuredViewportSize.Height; } if (Orientation == Orientation.Horizontal) { _extent.Height = _abstractPanel.SectionCount + ViewportHeight - 1; } else { _extent.Width = _abstractPanel.SectionCount + ViewportWidth - 1; } _owner.InvalidateScrollInfo(); } private void ResetScrollInfo() { _offset.X = 0; _offset.Y = 0; } private int GetNextSectionClosestIndex(int itemIndex) { var abstractItem = _abstractPanel[itemIndex]; if (abstractItem.Section < _abstractPanel.SectionCount - 1) { var ret = _abstractPanel. Where(x => x.Section == abstractItem.Section + 1). OrderBy(x => Math.Abs(x.SectionIndex - abstractItem.SectionIndex)). First(); return ret._index; } else return itemIndex; } private int GetLastSectionClosestIndex(int itemIndex) { var abstractItem = _abstractPanel[itemIndex]; if (abstractItem.Section > 0) { var ret = _abstractPanel. Where(x => x.Section == abstractItem.Section - 1). OrderBy(x => Math.Abs(x.SectionIndex - abstractItem.SectionIndex)). First(); return ret._index; } else return itemIndex; } private void NavigateDown() { var gen = _generator.GetItemContainerGeneratorForPanel(this); UIElement selected = (UIElement)Keyboard.FocusedElement; int itemIndex = gen.IndexFromContainer(selected); int depth = 0; while (itemIndex == -1) { selected = (UIElement)VisualTreeHelper.GetParent(selected); itemIndex = gen.IndexFromContainer(selected); depth++; } DependencyObject next = null; if (Orientation == Orientation.Horizontal) { int nextIndex = GetNextSectionClosestIndex(itemIndex); next = gen.ContainerFromIndex(nextIndex); while (next == null) { SetVerticalOffset(VerticalOffset + 1); UpdateLayout(); next = gen.ContainerFromIndex(nextIndex); } } else { if (itemIndex == _abstractPanel._itemCount - 1) return; next = gen.ContainerFromIndex(itemIndex + 1); while (next == null) { SetHorizontalOffset(HorizontalOffset + 1); UpdateLayout(); next = gen.ContainerFromIndex(itemIndex + 1); } } while (depth != 0) { next = VisualTreeHelper.GetChild(next, 0); depth--; } (next as UIElement).Focus(); } private void NavigateLeft() { var gen = _generator.GetItemContainerGeneratorForPanel(this); UIElement selected = (UIElement)Keyboard.FocusedElement; int itemIndex = gen.IndexFromContainer(selected); int depth = 0; while (itemIndex == -1) { selected = (UIElement)VisualTreeHelper.GetParent(selected); itemIndex = gen.IndexFromContainer(selected); depth++; } DependencyObject next = null; if (Orientation == Orientation.Vertical) { int nextIndex = GetLastSectionClosestIndex(itemIndex); next = gen.ContainerFromIndex(nextIndex); while (next == null) { SetHorizontalOffset(HorizontalOffset - 1); UpdateLayout(); next = gen.ContainerFromIndex(nextIndex); } } else { if (itemIndex == 0) return; next = gen.ContainerFromIndex(itemIndex - 1); while (next == null) { SetVerticalOffset(VerticalOffset - 1); UpdateLayout(); next = gen.ContainerFromIndex(itemIndex - 1); } } while (depth != 0) { next = VisualTreeHelper.GetChild(next, 0); depth--; } (next as UIElement).Focus(); } private void NavigateRight() { var gen = _generator.GetItemContainerGeneratorForPanel(this); UIElement selected = (UIElement)Keyboard.FocusedElement; int itemIndex = gen.IndexFromContainer(selected); int depth = 0; while (itemIndex == -1) { selected = (UIElement)VisualTreeHelper.GetParent(selected); itemIndex = gen.IndexFromContainer(selected); depth++; } DependencyObject next = null; if (Orientation == Orientation.Vertical) { int nextIndex = GetNextSectionClosestIndex(itemIndex); next = gen.ContainerFromIndex(nextIndex); while (next == null) { SetHorizontalOffset(HorizontalOffset + 1); UpdateLayout(); next = gen.ContainerFromIndex(nextIndex); } } else { if (itemIndex == _abstractPanel._itemCount - 1) return; next = gen.ContainerFromIndex(itemIndex + 1); while (next == null) { SetVerticalOffset(VerticalOffset + 1); UpdateLayout(); next = gen.ContainerFromIndex(itemIndex + 1); } } while (depth != 0) { next = VisualTreeHelper.GetChild(next, 0); depth--; } (next as UIElement).Focus(); } private void NavigateUp() { var gen = _generator.GetItemContainerGeneratorForPanel(this); UIElement selected = (UIElement)Keyboard.FocusedElement; int itemIndex = gen.IndexFromContainer(selected); int depth = 0; while (itemIndex == -1) { selected = (UIElement)VisualTreeHelper.GetParent(selected); itemIndex = gen.IndexFromContainer(selected); depth++; } DependencyObject next = null; if (Orientation == Orientation.Horizontal) { int nextIndex = GetLastSectionClosestIndex(itemIndex); next = gen.ContainerFromIndex(nextIndex); while (next == null) { SetVerticalOffset(VerticalOffset - 1); UpdateLayout(); next = gen.ContainerFromIndex(nextIndex); } } else { if (itemIndex == 0) return; next = gen.ContainerFromIndex(itemIndex - 1); while (next == null) { SetHorizontalOffset(HorizontalOffset - 1); UpdateLayout(); next = gen.ContainerFromIndex(itemIndex - 1); } } while (depth != 0) { next = VisualTreeHelper.GetChild(next, 0); depth--; } (next as UIElement).Focus(); } #endregion #region Override protected override void OnKeyDown(KeyEventArgs e) { switch (e.Key) { case Key.Down: NavigateDown(); e.Handled = true; break; case Key.Left: NavigateLeft(); e.Handled = true; break; case Key.Right: NavigateRight(); e.Handled = true; break; case Key.Up: NavigateUp(); e.Handled = true; break; default: base.OnKeyDown(e); break; } } protected override void OnItemsChanged(object sender, ItemsChangedEventArgs args) { base.OnItemsChanged(sender, args); _abstractPanel = null; ResetScrollInfo(); } protected override void OnInitialized(EventArgs e) { this.SizeChanged += new SizeChangedEventHandler(this.Resizing); base.OnInitialized(e); _itemsControl = ItemsControl.GetItemsOwner(this); _children = InternalChildren; _generator = ItemContainerGenerator; } protected override Size MeasureOverride(Size availableSize) { if (_itemsControl == null || _itemsControl.Items.Count == 0) return availableSize; if (_abstractPanel == null) _abstractPanel = new WrapPanelAbstraction(_itemsControl.Items.Count); _pixelMeasuredViewport = availableSize; _realizedChildLayout.Clear(); Size realizedFrameSize = availableSize; int itemCount = _itemsControl.Items.Count; int firstVisibleIndex = GetFirstVisibleIndex(); GeneratorPosition startPos = _generator.GeneratorPositionFromIndex(firstVisibleIndex); int childIndex = (startPos.Offset == 0) ? startPos.Index : startPos.Index + 1; int current = firstVisibleIndex; int visibleSections = 1; using (_generator.StartAt(startPos, GeneratorDirection.Forward, true)) { bool stop = false; bool isHorizontal = Orientation == Orientation.Horizontal; double currentX = 0; double currentY = 0; double maxItemSize = 0; int currentSection = GetFirstVisibleSection(); while (current < itemCount) { bool newlyRealized; // Get or create the child UIElement child = _generator.GenerateNext(out newlyRealized) as UIElement; if (newlyRealized) { // Figure out if we need to insert the child at the end or somewhere in the middle if (childIndex >= _children.Count) { base.AddInternalChild(child); } else { base.InsertInternalChild(childIndex, child); } _generator.PrepareItemContainer(child); child.Measure(ChildSlotSize); } else { // The child has already been created, let's be sure it's in the right spot Debug.Assert(child == _children[childIndex], "Wrong child was generated"); } childSize = child.DesiredSize; Rect childRect = new Rect(new Point(currentX, currentY), childSize); if (isHorizontal) { maxItemSize = Math.Max(maxItemSize, childRect.Height); if (childRect.Right > realizedFrameSize.Width) //wrap to a new line { currentY = currentY + maxItemSize; currentX = 0; maxItemSize = childRect.Height; childRect.X = currentX; childRect.Y = currentY; currentSection++; visibleSections++; } if (currentY > realizedFrameSize.Height) stop = true; currentX = childRect.Right; } else { maxItemSize = Math.Max(maxItemSize, childRect.Width); if (childRect.Bottom > realizedFrameSize.Height) //wrap to a new column { currentX = currentX + maxItemSize; currentY = 0; maxItemSize = childRect.Width; childRect.X = currentX; childRect.Y = currentY; currentSection++; visibleSections++; } if (currentX > realizedFrameSize.Width) stop = true; currentY = childRect.Bottom; } _realizedChildLayout.Add(child, childRect); _abstractPanel.SetItemSection(current, currentSection); if (stop) break; current++; childIndex++; } } CleanUpItems(firstVisibleIndex, current - 1); ComputeExtentAndViewport(availableSize, visibleSections); return availableSize; } protected override Size ArrangeOverride(Size finalSize) { if (_children != null) { foreach (UIElement child in _children) { var layoutInfo = _realizedChildLayout[child]; child.Arrange(layoutInfo); } } return finalSize; } #endregion #region IScrollInfo Members private bool _canHScroll = false; public bool CanHorizontallyScroll { get { return _canHScroll; } set { _canHScroll = value; } } private bool _canVScroll = false; public bool CanVerticallyScroll { get { return _canVScroll; } set { _canVScroll = value; } } public double ExtentHeight { get { return _extent.Height; } } public double ExtentWidth { get { return _extent.Width; } } public double HorizontalOffset { get { return _offset.X; } } public double VerticalOffset { get { return _offset.Y; } } public void LineDown() { if (Orientation == Orientation.Vertical) SetVerticalOffset(VerticalOffset + 20); else SetVerticalOffset(VerticalOffset + 1); } public void LineLeft() { if (Orientation == Orientation.Horizontal) SetHorizontalOffset(HorizontalOffset - 20); else SetHorizontalOffset(HorizontalOffset - 1); } public void LineRight() { if (Orientation == Orientation.Horizontal) SetHorizontalOffset(HorizontalOffset + 20); else SetHorizontalOffset(HorizontalOffset + 1); } public void LineUp() { if (Orientation == Orientation.Vertical) SetVerticalOffset(VerticalOffset - 20); else SetVerticalOffset(VerticalOffset - 1); } public Rect MakeVisible(Visual visual, Rect rectangle) { var gen = (ItemContainerGenerator)_generator.GetItemContainerGeneratorForPanel(this); var element = (UIElement)visual; int itemIndex = gen.IndexFromContainer(element); while (itemIndex == -1) { element = (UIElement)VisualTreeHelper.GetParent(element); itemIndex = gen.IndexFromContainer(element); } int section = _abstractPanel[itemIndex].Section; Rect elementRect = _realizedChildLayout[element]; if (Orientation == Orientation.Horizontal) { double viewportHeight = _pixelMeasuredViewport.Height; if (elementRect.Bottom > viewportHeight) _offset.Y += 1; else if (elementRect.Top < 0) _offset.Y -= 1; } else { double viewportWidth = _pixelMeasuredViewport.Width; if (elementRect.Right > viewportWidth) _offset.X += 1; else if (elementRect.Left < 0) _offset.X -= 1; } InvalidateMeasure(); return elementRect; } public void MouseWheelDown() { PageDown(); } public void MouseWheelLeft() { PageLeft(); } public void MouseWheelRight() { PageRight(); } public void MouseWheelUp() { PageUp(); } public void PageDown() { SetVerticalOffset(VerticalOffset + _viewport.Height * 0.8); } public void PageLeft() { SetHorizontalOffset(HorizontalOffset - _viewport.Width * 0.8); } public void PageRight() { SetHorizontalOffset(HorizontalOffset + _viewport.Width * 0.8); } public void PageUp() { SetVerticalOffset(VerticalOffset - _viewport.Height * 0.8); } private ScrollViewer _owner; public ScrollViewer ScrollOwner { get { return _owner; } set { _owner = value; } } public void SetHorizontalOffset(double offset) { if (offset < 0 || _viewport.Width >= _extent.Width) { offset = 0; } else { if (offset + _viewport.Width >= _extent.Width) { offset = _extent.Width - _viewport.Width; } } _offset.X = offset; if (_owner != null) _owner.InvalidateScrollInfo(); InvalidateMeasure(); firstIndex = GetFirstVisibleIndex(); } public void SetVerticalOffset(double offset) { if (offset < 0 || _viewport.Height >= _extent.Height) { offset = 0; } else { if (offset + _viewport.Height >= _extent.Height) { offset = _extent.Height - _viewport.Height; } } _offset.Y = offset; if (_owner != null) _owner.InvalidateScrollInfo(); //_trans.Y = -offset; InvalidateMeasure(); firstIndex = GetFirstVisibleIndex(); } public double ViewportHeight { get { return _viewport.Height; } } public double ViewportWidth { get { return _viewport.Width; } } #endregion #region helper data structures class ItemAbstraction { public ItemAbstraction(WrapPanelAbstraction panel, int index) { _panel = panel; _index = index; } WrapPanelAbstraction _panel; public readonly int _index; int _sectionIndex = -1; public int SectionIndex { get { if (_sectionIndex == -1) { return _index % _panel._averageItemsPerSection - 1; } return _sectionIndex; } set { if (_sectionIndex == -1) _sectionIndex = value; } } int _section = -1; public int Section { get { if (_section == -1) { return _index / _panel._averageItemsPerSection; } return _section; } set { if (_section == -1) _section = value; } } } class WrapPanelAbstraction : IEnumerable<ItemAbstraction> { public WrapPanelAbstraction(int itemCount) { List<ItemAbstraction> items = new List<ItemAbstraction>(itemCount); for (int i = 0; i < itemCount; i++) { ItemAbstraction item = new ItemAbstraction(this, i); items.Add(item); } Items = new ReadOnlyCollection<ItemAbstraction>(items); _averageItemsPerSection = itemCount; _itemCount = itemCount; } public readonly int _itemCount; public int _averageItemsPerSection; private int _currentSetSection = -1; private int _currentSetItemIndex = -1; private int _itemsInCurrentSecction = 0; private object _syncRoot = new object(); public int SectionCount { get { int ret = _currentSetSection + 1; if (_currentSetItemIndex + 1 < Items.Count) { int itemsLeft = Items.Count - _currentSetItemIndex; ret += itemsLeft / _averageItemsPerSection + 1; } return ret; } } private ReadOnlyCollection<ItemAbstraction> Items { get; set; } public void SetItemSection(int index, int section) { lock (_syncRoot) { if (section <= _currentSetSection + 1 && index == _currentSetItemIndex + 1) { _currentSetItemIndex++; Items[index].Section = section; if (section == _currentSetSection + 1) { _currentSetSection = section; if (section > 0) { _averageItemsPerSection = (index) / (section); } _itemsInCurrentSecction = 1; } else _itemsInCurrentSecction++; Items[index].SectionIndex = _itemsInCurrentSecction - 1; } } } public ItemAbstraction this[int index] { get { return Items[index]; } } #region IEnumerable<ItemAbstraction> Members public IEnumerator<ItemAbstraction> GetEnumerator() { return Items.GetEnumerator(); } #endregion #region IEnumerable Members System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { return GetEnumerator(); } #endregion } #endregion}
VirtualizingUniformGridPanel
class VirtualizingUniformGridPanel : VirtualizingPanel, IScrollInfo{ private Size _extent = new Size(0, 0); private Size _viewport = new Size(0, 0); private Point _offset = new Point(0, 0); private bool _canHorizontallyScroll = false; private bool _canVerticallyScroll = false; private ScrollViewer _owner; private int _scrollLength = 25; //----------------------------------------- // // Dependency Properties // //----------------------------------------- #region Dependency Properties /// <summary> /// Columns DependencyProperty /// </summary> public static readonly DependencyProperty ColumnsProperty = DependencyProperty.Register("Columns", typeof(int), typeof(VirtualizingUniformGridPanel), new FrameworkPropertyMetadata(1, FrameworkPropertyMetadataOptions.AffectsArrange | FrameworkPropertyMetadataOptions.AffectsMeasure)); /// <summary> /// Rows DependencyProperty /// </summary> public static readonly DependencyProperty RowsProperty = DependencyProperty.Register("Rows", typeof(int), typeof(VirtualizingUniformGridPanel), new FrameworkPropertyMetadata(1, FrameworkPropertyMetadataOptions.AffectsArrange | FrameworkPropertyMetadataOptions.AffectsMeasure)); /// <summary> /// Orientation DependencyProperty /// </summary> public static readonly DependencyProperty OrientationProperty = DependencyProperty.RegisterAttached("Orientation", typeof(Orientation), typeof(VirtualizingUniformGridPanel), new FrameworkPropertyMetadata(Orientation.Vertical, FrameworkPropertyMetadataOptions.AffectsArrange | FrameworkPropertyMetadataOptions.AffectsMeasure)); #endregion Dependency Properties //----------------------------------------- // // Public Properties // //----------------------------------------- #region Public Properties /// <summary> /// Get/Set the amount of columns this grid should have /// </summary> public int Columns { get { return (int)this.GetValue(ColumnsProperty); } set { this.SetValue(ColumnsProperty, value); } } /// <summary> /// Get/Set the amount of rows this grid should have /// </summary> public int Rows { get { return (int)this.GetValue(RowsProperty); } set { this.SetValue(RowsProperty, value); } } /// <summary> /// Get/Set the orientation of the panel /// </summary> public Orientation Orientation { get { return (Orientation)this.GetValue(OrientationProperty); } set { this.SetValue(OrientationProperty, value); } } #endregion Public Properties //----------------------------------------- // // Overrides // //----------------------------------------- #region Overrides /// <summary> /// When items are removed, remove the corresponding UI if necessary /// </summary> /// <param name="sender"></param> /// <param name="args"></param> protected override void OnItemsChanged(object sender, ItemsChangedEventArgs args) { switch (args.Action) { case NotifyCollectionChangedAction.Remove: case NotifyCollectionChangedAction.Replace: case NotifyCollectionChangedAction.Move: RemoveInternalChildRange(args.Position.Index, args.ItemUICount); break; } } /// <summary> /// Measure the children /// </summary> /// <param name="availableSize">Size available</param> /// <returns>Size desired</returns> protected override Size MeasureOverride(Size availableSize) { UpdateScrollInfo(availableSize); int firstVisibleItemIndex, lastVisibleItemIndex; GetVisibleRange(out firstVisibleItemIndex, out lastVisibleItemIndex); // We need to access InternalChildren before the generator to work around a bug UIElementCollection children = this.InternalChildren; IItemContainerGenerator generator = this.ItemContainerGenerator; // Get the generator position of the first visible data item GeneratorPosition startPos = generator.GeneratorPositionFromIndex(firstVisibleItemIndex); // Get index where we'd insert the child for this position. If the item is realized // (position.Offset == 0), it's just position.Index, otherwise we have to add one to // insert after the corresponding child int childIndex = (startPos.Offset == 0) ? startPos.Index : startPos.Index + 1; using (generator.StartAt(startPos, GeneratorDirection.Forward, true)) { for (int itemIndex = firstVisibleItemIndex; itemIndex <= lastVisibleItemIndex; ++itemIndex, ++childIndex) { bool newlyRealized; // Get or create the child UIElement child = generator.GenerateNext(out newlyRealized) as UIElement; childIndex = Math.Max(0, childIndex); if (newlyRealized) { // Figure out if we need to insert the child at the end or somewhere in the middle if (childIndex >= children.Count) { base.AddInternalChild(child); } else { base.InsertInternalChild(childIndex, child); } generator.PrepareItemContainer(child); } else { // The child has already been created, let's be sure it's in the right spot Debug.Assert(child == children[childIndex], "Wrong child was generated"); } // Measurements will depend on layout algorithm child.Measure(GetChildSize(availableSize)); } } // Note: this could be deferred to idle time for efficiency CleanUpItems(firstVisibleItemIndex, lastVisibleItemIndex); if (availableSize.Height.Equals(double.PositiveInfinity)) { Debug.WriteLine(_extent); return new Size(200, 200); } return availableSize; } /// <summary> /// Arrange the children /// </summary> /// <param name="finalSize">Size available</param> /// <returns>Size used</returns> protected override Size ArrangeOverride(Size finalSize) { IItemContainerGenerator generator = this.ItemContainerGenerator; UpdateScrollInfo(finalSize); for (int i = 0; i < this.Children.Count; i++) { UIElement child = this.Children[i]; int itemIndex = generator.IndexFromGeneratorPosition(new GeneratorPosition(i, 0)); ArrangeChild(itemIndex, child, finalSize); } return finalSize; } #endregion Overrides //----------------------------------------- // // Layout Specific Code // //----------------------------------------- #region Layout Specific Code /// <summary> /// Revisualizes items that are no longer visible /// </summary> /// <param name="minDesiredGenerated">first item index that should be visible</param> /// <param name="maxDesiredGenerated">last item index that should be visible</param> private void CleanUpItems(int minDesiredGenerated, int maxDesiredGenerated) { UIElementCollection children = this.InternalChildren; IItemContainerGenerator generator = this.ItemContainerGenerator; for (int i = children.Count - 1; i >= 0; i--) { GeneratorPosition childGeneratorPos = new GeneratorPosition(i, 0); int itemIndex = generator.IndexFromGeneratorPosition(childGeneratorPos); if (itemIndex < minDesiredGenerated || itemIndex > maxDesiredGenerated) { generator.Remove(childGeneratorPos, 1); RemoveInternalChildRange(i, 1); } } } /// <summary> /// Calculate the extent of the view based on the available size /// </summary> /// <param name="availableSize"></param> /// <returns></returns> private Size MeasureExtent(Size availableSize, int itemsCount) { Size childSize = GetChildSize(availableSize); if (this.Orientation == System.Windows.Controls.Orientation.Horizontal) { return new Size((this.Columns * childSize.Width) * Math.Ceiling((double)itemsCount / (this.Columns * this.Rows)), _viewport.Height); } else { var pageHeight = (this.Rows * childSize.Height); var sizeWidth = _viewport.Width; var sizeHeight = pageHeight * Math.Ceiling((double)itemsCount / (this.Rows * this.Columns)); return new Size(sizeWidth, sizeHeight); } } /// <summary> /// Arrange the individual children /// </summary> /// <param name="index"></param> /// <param name="child"></param> /// <param name="finalSize"></param> private void ArrangeChild(int index, UIElement child, Size finalSize) { int row = index / this.Columns; int column = index % this.Columns; double xPosition, yPosition; int currentPage; Size childSize = GetChildSize(finalSize); if (this.Orientation == System.Windows.Controls.Orientation.Horizontal) { currentPage = (int)Math.Floor((double)index / (this.Columns * this.Rows)); xPosition = (currentPage * this._viewport.Width) + (column * childSize.Width); yPosition = (row % this.Rows) * childSize.Height; xPosition -= this._offset.X; yPosition -= this._offset.Y; } else { xPosition = (column * childSize.Width) - this._offset.X; yPosition = (row * childSize.Height) - this._offset.Y; } child.Arrange(new Rect(xPosition, yPosition, childSize.Width, childSize.Height)); } /// <summary> /// Get the size of the child element /// </summary> /// <param name="availableSize"></param> /// <returns>Returns the size of the child</returns> private Size GetChildSize(Size availableSize) { double width = availableSize.Width / this.Columns; double height = availableSize.Height / this.Rows; return new Size(width, height); } /// <summary> /// Get the range of children that are visible /// </summary> /// <param name="firstVisibleItemIndex">The item index of the first visible item</param> /// <param name="lastVisibleItemIndex">The item index of the last visible item</param> private void GetVisibleRange(out int firstVisibleItemIndex, out int lastVisibleItemIndex) { Size childSize = GetChildSize(this._extent); int pageSize = this.Columns * this.Rows; int pageNumber = this.Orientation == System.Windows.Controls.Orientation.Horizontal ? (int)Math.Floor((double)this._offset.X / this._viewport.Width) : (int)Math.Floor((double)this._offset.Y / this._viewport.Height); firstVisibleItemIndex = (pageNumber * pageSize); lastVisibleItemIndex = firstVisibleItemIndex + (pageSize * 2) - 1; ItemsControl itemsControl = ItemsControl.GetItemsOwner(this); int itemCount = itemsControl.HasItems ? itemsControl.Items.Count : 0; if (lastVisibleItemIndex >= itemCount) { lastVisibleItemIndex = itemCount - 1; } } #endregion //----------------------------------------- // // IScrollInfo Implementation // //----------------------------------------- #region IScrollInfo Implementation public bool CanHorizontallyScroll { get { return _canHorizontallyScroll; } set { _canHorizontallyScroll = value; } } public bool CanVerticallyScroll { get { return _canVerticallyScroll; } set { _canVerticallyScroll = value; } } /// <summary> /// Get the extent height /// </summary> public double ExtentHeight { get { return this._extent.Height; } } /// <summary> /// Get the extent width /// </summary> public double ExtentWidth { get { return this._extent.Width; } } /// <summary> /// Get the current horizontal offset /// </summary> public double HorizontalOffset { get { return this._offset.X; } } /// <summary> /// Get the current vertical offset /// </summary> public double VerticalOffset { get { return this._offset.Y; } } /// <summary> /// Get/Set the scrollowner /// </summary> public System.Windows.Controls.ScrollViewer ScrollOwner { get { return this._owner; } set { this._owner = value; } } /// <summary> /// Get the Viewport Height /// </summary> public double ViewportHeight { get { return _viewport.Height; } } /// <summary> /// Get the Viewport Width /// </summary> public double ViewportWidth { get { return _viewport.Width; } } public void LineLeft() { this.SetHorizontalOffset(this._offset.X - _scrollLength); } public void LineRight() { this.SetHorizontalOffset(this._offset.X + _scrollLength); } public void LineUp() { this.SetVerticalOffset(this._offset.Y - _scrollLength); } public void LineDown() { this.SetVerticalOffset(this._offset.Y + _scrollLength); } public Rect MakeVisible(System.Windows.Media.Visual visual, Rect rectangle) { return new Rect(); } public void MouseWheelDown() { if (this.Orientation == System.Windows.Controls.Orientation.Horizontal) { this.SetHorizontalOffset(this._offset.X + _scrollLength); } else { this.SetVerticalOffset(this._offset.Y + _scrollLength); } } public void MouseWheelUp() { if (this.Orientation == System.Windows.Controls.Orientation.Horizontal) { this.SetHorizontalOffset(this._offset.X - _scrollLength); } else { this.SetVerticalOffset(this._offset.Y - _scrollLength); } } public void MouseWheelLeft() { return; } public void MouseWheelRight() { return; } public void PageDown() { this.SetVerticalOffset(this._offset.Y + _viewport.Width); } public void PageUp() { this.SetVerticalOffset(this._offset.Y - _viewport.Width); } public void PageLeft() { this.SetHorizontalOffset(this._offset.X - _viewport.Width); } public void PageRight() { this.SetHorizontalOffset(this._offset.X + _viewport.Width); } public void SetHorizontalOffset(double offset) { _offset.X = Math.Max(0, offset); if (_owner != null) { _owner.InvalidateScrollInfo(); } InvalidateMeasure(); } public void SetVerticalOffset(double offset) { _offset.Y = Math.Max(0, offset); if (_owner != null) { _owner.InvalidateScrollInfo(); } InvalidateMeasure(); } private void UpdateScrollInfo(Size availableSize) { // See how many items there are ItemsControl itemsControl = ItemsControl.GetItemsOwner(this); int itemCount = itemsControl.HasItems ? itemsControl.Items.Count : 0; Size extent = MeasureExtent(availableSize, itemCount); // Update extent if (extent != _extent) { _extent = extent; if (_owner != null) _owner.InvalidateScrollInfo(); } // Update viewport if (availableSize != _viewport) { _viewport = availableSize; if (_owner != null) _owner.InvalidateScrollInfo(); } } #endregion IScrollInfo Implementation}
使用
<ListBox ScrollViewer.VerticalScrollBarVisibility="Hidden"> <ListBox.ItemsPanel> <ItemsPanelTemplate> <control:VirtualizingUniformGridPanel Rows="2" Columns="3" Orientation="Vertical"/> </ItemsPanelTemplate> </ListBox.ItemsPanel> <ListBox.Items> <ListBoxItem Margin="1" BorderBrush="Red" BorderThickness="2">1</ListBoxItem> <ListBoxItem Margin="1" BorderBrush="Green" BorderThickness="2">2</ListBoxItem> <ListBoxItem Margin="1" BorderBrush="Blue" BorderThickness="2">3</ListBoxItem> <ListBoxItem Margin="1" BorderBrush="BlueViolet" BorderThickness="2">4</ListBoxItem> <ListBoxItem Margin="1" BorderBrush="RosyBrown" BorderThickness="2">5</ListBoxItem> <ListBoxItem Margin="1" BorderBrush="RoyalBlue" BorderThickness="2">6</ListBoxItem> <ListBoxItem Margin="1" BorderBrush="Orange" BorderThickness="2">7</ListBoxItem> <ListBoxItem Margin="1" BorderBrush="OrangeRed" BorderThickness="2">8</ListBoxItem> <ListBoxItem Margin="1" BorderBrush="GreenYellow" BorderThickness="2">9</ListBoxItem> <ListBoxItem Margin="1" BorderBrush="YellowGreen" BorderThickness="2">10</ListBoxItem> </ListBox.Items></ListBox>
阅读全文
0 0
- WPF Virtualizing Panel
- wpf 笔记 Panel
- WPF Pop up Panel Hidden
- WPF Panel的性能分析
- 【6】Virtualizing disk performance
- WPF下的布局(Layout、Panel)小记
- WPF Panel resize end event logic
- panel
- panel
- WPF Panel内容模型、Decorator内容模型及其他(11)
- panel添加panel
- WPF学习记录-布局[摘抄自博客园(xiepeixing<WPF布局该如何选用panel>与(DotNet菜园<WPF入门教程系列七——布局之WrapPanel与StackPanel(二)>))]
- WPF
- WPF
- WPF
- WPF
- WPF
- WPF
- speex中的AEC框架介绍(in C)
- android开发 NDK 编译和使用静态库、动态库
- QT将信息保存到某个路径下(2)
- Python3之hashlib模块
- Maven工程运行报错:java.lang.ClassNotFoundException: org.springframework.web.context.ContextLoaderListener
- WPF Virtualizing Panel
- basic
- 创意族贺小米七周年庆专题:国际“米淘”热潮
- Picture
- python读写excel文件
- php数组根据某一个键值,把相同键值的合并生成一个新的二维数组
- 使用linq.js操作后台JSON数据到前台select标签
- (优先队列)2506完美网络
- FFmpeg X264 H264编码指南[译]