| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439 | 
							- using System;
 
- using System.Collections.Generic;
 
- using System.Diagnostics;
 
- using System.Linq;
 
- using System.Text;
 
- using System.Threading.Tasks;
 
- using System.Windows;
 
- using System.Windows.Controls;
 
- using System.Windows.Controls.Primitives;
 
- using System.Windows.Media;
 
- namespace MECF.Framework.UI.Client.Ctrlib.Controls
 
- {
 
-     public class VirtualizingWrapPanel : VirtualizingPanel, IScrollInfo
 
-     {
 
-         private TranslateTransform trans = new TranslateTransform();
 
-         public VirtualizingWrapPanel()
 
-         {
 
-             this.RenderTransform = trans;
 
-         }
 
-         #region DependencyProperties
 
-         public static readonly DependencyProperty ChildWidthProperty = DependencyProperty.RegisterAttached("ChildWidth", typeof(double), typeof(VirtualizingWrapPanel), new FrameworkPropertyMetadata(200.0, FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsArrange));
 
-         public static readonly DependencyProperty ChildHeightProperty = DependencyProperty.RegisterAttached("ChildHeight", typeof(double), typeof(VirtualizingWrapPanel), new FrameworkPropertyMetadata(200.0, FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsArrange));
 
-         //鼠标每一次滚动 UI上的偏移
 
-         public static readonly DependencyProperty ScrollOffsetProperty = DependencyProperty.RegisterAttached("ScrollOffset", typeof(int), typeof(VirtualizingWrapPanel), new PropertyMetadata(10));
 
-         public int ScrollOffset
 
-         {
 
-             get { return Convert.ToInt32(GetValue(ScrollOffsetProperty)); }
 
-             set { SetValue(ScrollOffsetProperty, value); }
 
-         }
 
-         public double ChildWidth
 
-         {
 
-             get => Convert.ToDouble(GetValue(ChildWidthProperty));
 
-             set => SetValue(ChildWidthProperty, value);
 
-         }
 
-         public double ChildHeight
 
-         {
 
-             get => Convert.ToDouble(GetValue(ChildHeightProperty));
 
-             set => SetValue(ChildHeightProperty, value);
 
-         }
 
-         public Orientation Orientation
 
-         {
 
-             get => (Orientation)(GetValue(OrientationProperty));
 
-             set => SetValue(OrientationProperty, value);
 
-         }
 
-         public static readonly DependencyProperty OrientationProperty = DependencyProperty.RegisterAttached("Orientation", typeof(Orientation), typeof(VirtualizingWrapPanel), new FrameworkPropertyMetadata(Orientation.Horizontal, FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsArrange));
 
-         #endregion
 
-         int GetItemCount(DependencyObject element)
 
-         {
 
-             var itemsControl = ItemsControl.GetItemsOwner(element);
 
-             return itemsControl.HasItems ? itemsControl.Items.Count : 0;
 
-         }
 
-         int CalculateChildrenPerRow(Size availableSize)
 
-         {
 
-             int childPerRow = 0;
 
-             if (availableSize.Width == double.PositiveInfinity)
 
-                 childPerRow = this.Children.Count;
 
-             else
 
-             {
 
-                 childPerRow = Math.Max(1, Convert.ToInt32(Math.Floor(availableSize.Width / this.ChildWidth)));
 
-             }
 
-             return childPerRow;
 
-         }
 
-         int CalculateChildrenPerColumn(Size availableSize)
 
-         {
 
-             int childPerColumn = 0;
 
-             if (availableSize.Height == double.PositiveInfinity)
 
-                 childPerColumn = this.Children.Count;
 
-             else
 
-             {
 
-                 childPerColumn = Math.Max(1, Convert.ToInt32(Math.Floor(availableSize.Height / this.ChildHeight)));
 
-             }
 
-             return childPerColumn;
 
-         }
 
-         /// <summary>
 
-         /// width不超过availableSize的情况下,自身实际需要的Size(高度可能会超出availableSize)
 
-         /// </summary>
 
-         /// <param name="availableSize"></param>
 
-         /// <param name="itemsCount"></param>
 
-         /// <returns></returns>
 
-         Size CalculateExtent(Size availableSize, int itemsCount)
 
-         {
 
-             if (Orientation == Orientation.Horizontal)
 
-             {
 
-                 int childPerRow = CalculateChildrenPerRow(availableSize);//现有宽度下 一行可以最多容纳多少个
 
-                 return new Size(childPerRow * this.ChildWidth, this.ChildHeight * Math.Ceiling(Convert.ToDouble(itemsCount) / childPerRow));
 
-             }
 
-             else if (Orientation == Orientation.Vertical)
 
-             {
 
-                 int childPerColumn = CalculateChildrenPerColumn(availableSize);//现有高度下 一行可以最多容纳多少个
 
-                 return new Size(Math.Ceiling(Convert.ToDouble(itemsCount) / childPerColumn) * this.ChildWidth, this.ChildHeight * childPerColumn);
 
-             }
 
-             else
 
-             {
 
-                 return availableSize;
 
-             }
 
-         }
 
-         /// <summary>
 
-         /// 更新滚动条
 
-         /// </summary>
 
-         /// <param name="availableSize"></param>
 
-         void UpdateScrollInfo(Size availableSize)
 
-         {
 
-             var extent = CalculateExtent(availableSize, GetItemCount(this));//extent 自己实际需要
 
-             if (extent != this.extent)
 
-             {
 
-                 this.extent = extent;
 
-                 this.ScrollOwner.InvalidateScrollInfo();
 
-             }
 
-             if (availableSize != this.viewPort)
 
-             {
 
-                 this.viewPort = availableSize;
 
-                 this.ScrollOwner.InvalidateScrollInfo();
 
-             }
 
-         }
 
-         /// <summary>
 
-         /// 获取所有item,在可视区域内第一个item和最后一个item的索引
 
-         /// </summary>
 
-         /// <param name="firstIndex"></param>
 
-         /// <param name="lastIndex"></param>
 
-         void GetVisiableRange(ref int firstIndex, ref int lastIndex)
 
-         {
 
-             if (Orientation == Orientation.Horizontal)
 
-             {
 
-                 int childPerRow = CalculateChildrenPerRow(this.extent);
 
-                 firstIndex = Convert.ToInt32(Math.Floor(this.offset.Y / this.ChildHeight)) * childPerRow;
 
-                 if (!double.IsInfinity(this.viewPort.Height))
 
-                 {
 
-                     lastIndex = Convert.ToInt32(Math.Ceiling((this.offset.Y + this.viewPort.Height) / this.ChildHeight)) * childPerRow - 1;
 
-                     int itemsCount = GetItemCount(this);
 
-                     if (lastIndex >= itemsCount)
 
-                         lastIndex = itemsCount - 1;
 
-                 }
 
-             }
 
-             else if (Orientation == Orientation.Vertical)
 
-             {
 
-                 int childPerColumn = CalculateChildrenPerColumn(this.extent);
 
-                 firstIndex = Convert.ToInt32(Math.Ceiling(this.offset.X / this.ChildWidth)) * childPerColumn;
 
-                 if (!double.IsInfinity(this.viewPort.Width))
 
-                 {
 
-                     lastIndex = Convert.ToInt32(Math.Ceiling((this.offset.X + this.viewPort.Width) / this.ChildWidth)) * childPerColumn - 1;
 
-                     int itemsCount = GetItemCount(this);
 
-                     if (lastIndex >= itemsCount)
 
-                         lastIndex = itemsCount - 1;
 
-                 }
 
-             }
 
-         }
 
-         /// <summary>
 
-         /// 将不在可视区域内的item 移除
 
-         /// </summary>
 
-         /// <param name="startIndex">可视区域开始索引</param>
 
-         /// <param name="endIndex">可视区域结束索引</param>
 
-         void CleanUpItems(int startIndex, int endIndex)
 
-         {
 
-             var children = this.InternalChildren;
 
-             var generator = this.ItemContainerGenerator;
 
-             for (int i = children.Count - 1; i >= 0; i--)
 
-             {
 
-                 var childGeneratorPosi = new GeneratorPosition(i, 0);
 
-                 int itemIndex = generator.IndexFromGeneratorPosition(childGeneratorPosi);
 
-                 if (itemIndex < startIndex || itemIndex > endIndex)
 
-                 {
 
-                     generator.Remove(childGeneratorPosi, 1);
 
-                     RemoveInternalChildRange(i, 1);
 
-                 }
 
-             }
 
-         }
 
-         /// <summary>
 
-         /// scroll/availableSize/添加删除元素 改变都会触发  edit元素不会改变
 
-         /// </summary>
 
-         /// <param name="availableSize"></param>
 
-         /// <returns></returns>
 
-         protected override Size MeasureOverride(Size availableSize)
 
-         {
 
-             this.UpdateScrollInfo(availableSize);//availableSize更新后,更新滚动条
 
-             int firstVisiableIndex = 0, lastVisiableIndex = 0;
 
-             GetVisiableRange(ref firstVisiableIndex, ref lastVisiableIndex);//availableSize更新后,获取当前viewport内可放置的item的开始和结束索引  firstIdnex-lastIndex之间的item可能部分在viewport中也可能都不在viewport中。
 
-             UIElementCollection children = this.InternalChildren;//因为配置了虚拟化,所以children的个数一直是viewport区域内的个数,如果没有虚拟化则是ItemSource的整个的个数
 
-             IItemContainerGenerator generator = this.ItemContainerGenerator;
 
-             //获得第一个可被显示的item的位置
 
-             GeneratorPosition startPosi = generator.GeneratorPositionFromIndex(firstVisiableIndex);
 
-             int childIndex = (startPosi.Offset == 0) ? startPosi.Index : startPosi.Index + 1;//startPosi在chilren中的索引
 
-             using (generator.StartAt(startPosi, GeneratorDirection.Forward, true))
 
-             {
 
-                 int itemIndex = firstVisiableIndex;
 
-                 while (itemIndex <= lastVisiableIndex)//生成lastVisiableIndex-firstVisiableIndex个item
 
-                 {
 
-                     bool newlyRealized = false;
 
-                     var child = generator.GenerateNext(out newlyRealized) as UIElement;
 
-                     if (child == null) return availableSize;
 
-                     if (newlyRealized)
 
-                     {
 
-                         if (childIndex >= children.Count)
 
-                             base.AddInternalChild(child);
 
-                         else
 
-                         {
 
-                             base.InsertInternalChild(childIndex, child);
 
-                         }
 
-                         generator.PrepareItemContainer(child);
 
-                     }
 
-                     else
 
-                     {
 
-                         //处理 正在显示的child被移除了这种情况
 
-                         if (!child.Equals(children[childIndex]))
 
-                         {
 
-                             base.RemoveInternalChildRange(childIndex, 1);
 
-                         }
 
-                     }
 
-                     child.Measure(new Size(this.ChildWidth, this.ChildHeight));
 
-                     //child.DesiredSize;//child想要的size
 
-                     itemIndex++;
 
-                     childIndex++;
 
-                 }
 
-             }
 
-             CleanUpItems(firstVisiableIndex, lastVisiableIndex);
 
-             return new Size(double.IsInfinity(availableSize.Width) ? 0 : availableSize.Width, double.IsInfinity(availableSize.Height) ? 0 : availableSize.Height);//自身想要的size
 
-         }
 
-         protected override Size ArrangeOverride(Size finalSize)
 
-         {
 
-             //Debug.WriteLine("----ArrangeOverride");
 
-             var generator = this.ItemContainerGenerator;
 
-             UpdateScrollInfo(finalSize);
 
-             if (Orientation == Orientation.Horizontal)
 
-             {
 
-                 int childPerRow = CalculateChildrenPerRow(finalSize);
 
-                 double availableItemWidth = finalSize.Width / childPerRow;
 
-                 for (int i = 0; i <= this.Children.Count - 1; i++)
 
-                 {
 
-                     var child = this.Children[i];
 
-                     int itemIndex = generator.IndexFromGeneratorPosition(new GeneratorPosition(i, 0));
 
-                     int row = 0;
 
-                     int column = 0;
 
-                     row = itemIndex / childPerRow;//current row
 
-                     column = itemIndex % childPerRow;
 
-                     double xCorrdForItem = 0;
 
-                     xCorrdForItem = column * availableItemWidth + (availableItemWidth - this.ChildWidth) / 2;
 
-                     Rect rec = new Rect(xCorrdForItem, row * this.ChildHeight, this.ChildWidth, this.ChildHeight);
 
-                     child.Arrange(rec);
 
-                 }
 
-                 return finalSize;
 
-             }
 
-             else if (Orientation == Orientation.Vertical)
 
-             {
 
-                 int childPerColumn = CalculateChildrenPerColumn(finalSize);
 
-                 double availableItemHeight = finalSize.Height / childPerColumn;
 
-                 for (int i = 0; i <= this.Children.Count - 1; i++)
 
-                 {
 
-                     var child = this.Children[i];
 
-                     int itemIndex = generator.IndexFromGeneratorPosition(new GeneratorPosition(i, 0));
 
-                     int row = 0;
 
-                     int column = 0;
 
-                     row = itemIndex % childPerColumn;
 
-                     column = i / childPerColumn;
 
-                     double xCorrdForItem = 0;
 
-                     xCorrdForItem = row * availableItemHeight + (availableItemHeight - this.ChildHeight) / 2;
 
-                     Rect rec = new Rect(column * this.ChildWidth, row * ChildHeight, this.ChildWidth, this.ChildHeight);
 
-                     child.Arrange(rec);
 
-                 }
 
-                 return finalSize;
 
-             }
 
-             else { return finalSize; }
 
-         }
 
-         protected override void OnRenderSizeChanged(SizeChangedInfo sizeInfo)
 
-         {
 
-             base.OnRenderSizeChanged(sizeInfo);
 
-             this.SetVerticalOffset(this.VerticalOffset);
 
-         }
 
-         protected override void OnClearChildren()
 
-         {
 
-             base.OnClearChildren();
 
-             this.SetVerticalOffset(0);
 
-         }
 
-         protected override void BringIndexIntoView(int index)
 
-         {
 
-             if (index < 0 || index >= Children.Count)
 
-                 throw new ArgumentOutOfRangeException();
 
-             if (Orientation == Orientation.Horizontal)
 
-             {
 
-                 int row = index / CalculateChildrenPerRow(RenderSize);
 
-                 SetVerticalOffset(row * this.ChildHeight);
 
-             }
 
-             else if (Orientation == Orientation.Vertical)
 
-             {
 
-                 int column = index / CalculateChildrenPerColumn(RenderSize);
 
-                 SetVerticalOffset(column * this.ChildWidth);
 
-             }
 
-         }
 
-         #region IScrollInfo Interface
 
-         public bool CanVerticallyScroll { get; set; }
 
-         public bool CanHorizontallyScroll { get; set; }
 
-         private Size extent = new Size(0, 0);
 
-         public double ExtentWidth => this.extent.Width;
 
-         public double ExtentHeight => this.extent.Height;
 
-         private Size viewPort = new Size(0, 0);
 
-         public double ViewportWidth => this.viewPort.Width;
 
-         public double ViewportHeight => this.viewPort.Height;
 
-         private Point offset;
 
-         public double HorizontalOffset => this.offset.Y;
 
-         public double VerticalOffset => this.offset.X;
 
-         public ScrollViewer ScrollOwner { get; set; } = new ScrollViewer();
 
-         public void LineDown()
 
-         {
 
-             this.SetVerticalOffset(this.HorizontalOffset + this.ScrollOffset);
 
-         }
 
-         public void LineLeft()
 
-         {
 
-             this.SetVerticalOffset(this.VerticalOffset - this.ChildWidth);
 
-         }
 
-         public void LineRight()
 
-         {
 
-             this.SetVerticalOffset(this.VerticalOffset + this.ChildWidth);
 
-         }
 
-         public void LineUp()
 
-         {
 
-             this.SetVerticalOffset(this.HorizontalOffset - this.ScrollOffset);
 
-         }
 
-         public Rect MakeVisible(Visual visual, Rect rectangle)
 
-         {
 
-             return new Rect();
 
-         }
 
-         public void MouseWheelDown()
 
-         {
 
-             this.SetVerticalOffset(this.VerticalOffset + this.ScrollOffset);
 
-         }
 
-         public void MouseWheelLeft()
 
-         {
 
-             throw new NotImplementedException();
 
-         }
 
-         public void MouseWheelRight()
 
-         {
 
-             throw new NotImplementedException();
 
-         }
 
-         public void MouseWheelUp()
 
-         {
 
-             this.SetVerticalOffset(this.VerticalOffset - this.ScrollOffset);
 
-         }
 
-         //临时借用到ScrollToLeftEnd
 
-         public void PageDown()
 
-         {
 
-             this.SetVerticalOffset(this.extent.Width - this.viewPort.Width);
 
-             //this.SetVerticalOffset(this.HorizontalOffset + this.viewPort.Height);
 
-         }
 
-         public void PageLeft()
 
-         {
 
-             this.SetVerticalOffset(this.VerticalOffset - this.viewPort.Width);
 
-         }
 
-         public void PageRight()
 
-         {
 
-             this.SetVerticalOffset(this.VerticalOffset + this.viewPort.Width);
 
-         }
 
-         //临时借用到ScrollToRightEnd
 
-         public void PageUp()
 
-         {
 
-             this.SetVerticalOffset(0);
 
-             //  this.SetVerticalOffset(this.HorizontalOffset - this.viewPort.Height);
 
-         }
 
-         public void ScrollToLeftEnd()
 
-         {
 
-             this.SetVerticalOffset(0);
 
-         }
 
-         public void SetHorizontalOffset(double offset)
 
-         {
 
-            
 
-         }
 
-         public void SetVerticalOffset(double offset)
 
-         {
 
-             if (Orientation == Orientation.Horizontal)
 
-             {
 
-                 if (offset < 0 || this.viewPort.Height >= this.extent.Height)
 
-                     offset = 0;
 
-                 else
 
-                     if (offset + this.viewPort.Height >= this.extent.Height)
 
-                     offset = this.extent.Height - this.viewPort.Height;
 
-                 this.offset.Y = offset;
 
-                 this.ScrollOwner?.InvalidateScrollInfo();
 
-                 this.trans.Y = -offset;
 
-                 this.InvalidateMeasure();
 
-             }
 
-             else if (Orientation == Orientation.Vertical)
 
-             {
 
-                 if (offset < 0 || this.viewPort.Width >= this.extent.Width)
 
-                     offset = 0;
 
-                 else
 
-                        if (offset + this.viewPort.Width >= this.extent.Width)
 
-                     offset = this.extent.Width - this.viewPort.Width;
 
-                 this.offset.X = offset;
 
-                 this.ScrollOwner?.InvalidateScrollInfo();
 
-                // this.trans.X = -offset;
 
-                 this.InvalidateMeasure();
 
-             }
 
-             //接下来会触发MeasureOverride()
 
-         }
 
-         #endregion
 
-     }
 
- }
 
 
  |