zoukankan      html  css  js  c++  java
  • 备份一个 VirtualizingWrapPanel ,支持虚拟化

      1 using System;
      2 using System.Collections.Generic;
      3 using System.Collections.ObjectModel;
      4 using System.ComponentModel;
      5 using System.Diagnostics;
      6 using System.Linq;
      7 using System.Windows;
      8 using System.Windows.Controls;
      9 using System.Windows.Controls.Primitives;
     10 using System.Windows.Input;
     11 using System.Windows.Media;
     12 
     13 namespace TreeViewDemo
     14 {
     15     /// <summary>
     16     /// 支持虚拟化的wrappanel
     17     /// </summary>
     18     public class VirtualizingWrapPanel : VirtualizingPanel, IScrollInfo
     19     {
     20         #region Fields
     21 
     22         UIElementCollection _children;
     23         ItemsControl _itemsControl;
     24         IItemContainerGenerator _generator;
     25         private Point _offset = new Point(0, 0);
     26         private Size _extent = new Size(0, 0);
     27         private Size _viewport = new Size(0, 0);
     28         private int firstIndex = 0;
     29         private Size childSize;
     30         private Size _pixelMeasuredViewport = new Size(0, 0);
     31         Dictionary<UIElement, Rect> _realizedChildLayout = new Dictionary<UIElement, Rect>();
     32         WrapPanelAbstraction _abstractPanel;
     33 
     34 
     35         #endregion
     36 
     37         #region Properties
     38 
     39         private Size ChildSlotSize
     40         {
     41             get
     42             {
     43                 return new Size(ItemWidth, ItemHeight);
     44             }
     45         }
     46 
     47         #endregion
     48 
     49         #region Dependency Properties
     50 
     51         [TypeConverter(typeof(LengthConverter))]
     52         public double ItemHeight
     53         {
     54             get
     55             {
     56                 return (double)base.GetValue(ItemHeightProperty);
     57             }
     58             set
     59             {
     60                 base.SetValue(ItemHeightProperty, value);
     61             }
     62         }
     63 
     64         [TypeConverter(typeof(LengthConverter))]
     65         public double ItemWidth
     66         {
     67             get
     68             {
     69                 return (double)base.GetValue(ItemWidthProperty);
     70             }
     71             set
     72             {
     73                 base.SetValue(ItemWidthProperty, value);
     74             }
     75         }
     76 
     77         public Orientation Orientation
     78         {
     79             get { return (Orientation)GetValue(OrientationProperty); }
     80             set { SetValue(OrientationProperty, value); }
     81         }
     82 
     83         public static readonly DependencyProperty ItemHeightProperty = DependencyProperty.Register("ItemHeight", typeof(double), typeof(VirtualizingWrapPanel), new FrameworkPropertyMetadata(double.PositiveInfinity));
     84         public static readonly DependencyProperty ItemWidthProperty = DependencyProperty.Register("ItemWidth", typeof(double), typeof(VirtualizingWrapPanel), new FrameworkPropertyMetadata(double.PositiveInfinity));
     85         public static readonly DependencyProperty OrientationProperty = StackPanel.OrientationProperty.AddOwner(typeof(VirtualizingWrapPanel), new FrameworkPropertyMetadata(Orientation.Horizontal));
     86 
     87         #endregion
     88 
     89         #region Methods
     90 
     91         public void SetFirstRowViewItemIndex(int index)
     92         {
     93             SetVerticalOffset((index) / Math.Floor((_viewport.Width) / childSize.Width));
     94             SetHorizontalOffset((index) / Math.Floor((_viewport.Height) / childSize.Height));
     95         }
     96 
     97         private void Resizing(object sender, EventArgs e)
     98         {
     99             if (_viewport.Width != 0)
    100             {
    101                 int firstIndexCache = firstIndex;
    102                 _abstractPanel = null;
    103                 MeasureOverride(_viewport);
    104                 SetFirstRowViewItemIndex(firstIndex);
    105                 firstIndex = firstIndexCache;
    106             }
    107         }
    108 
    109         public int GetFirstVisibleSection()
    110         {
    111             int section;
    112             var maxSection = _abstractPanel.Max(x => x.Section);
    113             if (Orientation == Orientation.Horizontal)
    114             {
    115                 section = (int)_offset.Y;
    116             }
    117             else
    118             {
    119                 section = (int)_offset.X;
    120             }
    121             if (section > maxSection)
    122                 section = maxSection;
    123             return section;
    124         }
    125 
    126         public int GetFirstVisibleIndex()
    127         {
    128             int section = GetFirstVisibleSection();
    129             var item = _abstractPanel.Where(x => x.Section == section).FirstOrDefault();
    130             if (item != null)
    131                 return item._index;
    132             return 0;
    133         }
    134 
    135         private void CleanUpItems(int minDesiredGenerated, int maxDesiredGenerated)
    136         {
    137             for (int i = _children.Count - 1; i >= 0; i--)
    138             {
    139                 GeneratorPosition childGeneratorPos = new GeneratorPosition(i, 0);
    140                 int itemIndex = _generator.IndexFromGeneratorPosition(childGeneratorPos);
    141                 if (itemIndex < minDesiredGenerated || itemIndex > maxDesiredGenerated)
    142                 {
    143                     _generator.Remove(childGeneratorPos, 1);
    144                     RemoveInternalChildRange(i, 1);
    145                 }
    146             }
    147         }
    148 
    149         private void ComputeExtentAndViewport(Size pixelMeasuredViewportSize, int visibleSections)
    150         {
    151             if (Orientation == Orientation.Horizontal)
    152             {
    153                 _viewport.Height = visibleSections;
    154                 _viewport.Width = pixelMeasuredViewportSize.Width;
    155             }
    156             else
    157             {
    158                 _viewport.Width = visibleSections;
    159                 _viewport.Height = pixelMeasuredViewportSize.Height;
    160             }
    161 
    162             if (Orientation == Orientation.Horizontal)
    163             {
    164                 _extent.Height = _abstractPanel.SectionCount + ViewportHeight - 1;
    165 
    166             }
    167             else
    168             {
    169                 _extent.Width = _abstractPanel.SectionCount + ViewportWidth - 1;
    170             }
    171             _owner.InvalidateScrollInfo();
    172         }
    173 
    174         private void ResetScrollInfo()
    175         {
    176             _offset.X = 0;
    177             _offset.Y = 0;
    178         }
    179 
    180         private int GetNextSectionClosestIndex(int itemIndex)
    181         {
    182             var abstractItem = _abstractPanel[itemIndex];
    183             if (abstractItem.Section < _abstractPanel.SectionCount - 1)
    184             {
    185                 var ret = _abstractPanel.
    186                     Where(x => x.Section == abstractItem.Section + 1).
    187                     OrderBy(x => Math.Abs(x.SectionIndex - abstractItem.SectionIndex)).
    188                     First();
    189                 return ret._index;
    190             }
    191             else
    192                 return itemIndex;
    193         }
    194 
    195         private int GetLastSectionClosestIndex(int itemIndex)
    196         {
    197             var abstractItem = _abstractPanel[itemIndex];
    198             if (abstractItem.Section > 0)
    199             {
    200                 var ret = _abstractPanel.
    201                     Where(x => x.Section == abstractItem.Section - 1).
    202                     OrderBy(x => Math.Abs(x.SectionIndex - abstractItem.SectionIndex)).
    203                     First();
    204                 return ret._index;
    205             }
    206             else
    207                 return itemIndex;
    208         }
    209 
    210         private void NavigateDown()
    211         {
    212             var gen = _generator.GetItemContainerGeneratorForPanel(this);
    213             UIElement selected = (UIElement)Keyboard.FocusedElement;
    214             int itemIndex = gen.IndexFromContainer(selected);
    215             int depth = 0;
    216             while (itemIndex == -1)
    217             {
    218                 selected = (UIElement)VisualTreeHelper.GetParent(selected);
    219                 itemIndex = gen.IndexFromContainer(selected);
    220                 depth++;
    221             }
    222             DependencyObject next = null;
    223             if (Orientation == Orientation.Horizontal)
    224             {
    225                 int nextIndex = GetNextSectionClosestIndex(itemIndex);
    226                 next = gen.ContainerFromIndex(nextIndex);
    227                 while (next == null)
    228                 {
    229                     SetVerticalOffset(VerticalOffset + 1);
    230                     UpdateLayout();
    231                     next = gen.ContainerFromIndex(nextIndex);
    232                 }
    233             }
    234             else
    235             {
    236                 if (itemIndex == _abstractPanel._itemCount - 1)
    237                     return;
    238                 next = gen.ContainerFromIndex(itemIndex + 1);
    239                 while (next == null)
    240                 {
    241                     SetHorizontalOffset(HorizontalOffset + 1);
    242                     UpdateLayout();
    243                     next = gen.ContainerFromIndex(itemIndex + 1);
    244                 }
    245             }
    246             while (depth != 0)
    247             {
    248                 next = VisualTreeHelper.GetChild(next, 0);
    249                 depth--;
    250             }
    251             (next as UIElement).Focus();
    252         }
    253 
    254         private void NavigateLeft()
    255         {
    256             var gen = _generator.GetItemContainerGeneratorForPanel(this);
    257 
    258             UIElement selected = (UIElement)Keyboard.FocusedElement;
    259             int itemIndex = gen.IndexFromContainer(selected);
    260             int depth = 0;
    261             while (itemIndex == -1)
    262             {
    263                 selected = (UIElement)VisualTreeHelper.GetParent(selected);
    264                 itemIndex = gen.IndexFromContainer(selected);
    265                 depth++;
    266             }
    267             DependencyObject next = null;
    268             if (Orientation == Orientation.Vertical)
    269             {
    270                 int nextIndex = GetLastSectionClosestIndex(itemIndex);
    271                 next = gen.ContainerFromIndex(nextIndex);
    272                 while (next == null)
    273                 {
    274                     SetHorizontalOffset(HorizontalOffset - 1);
    275                     UpdateLayout();
    276                     next = gen.ContainerFromIndex(nextIndex);
    277                 }
    278             }
    279             else
    280             {
    281                 if (itemIndex == 0)
    282                     return;
    283                 next = gen.ContainerFromIndex(itemIndex - 1);
    284                 while (next == null)
    285                 {
    286                     SetVerticalOffset(VerticalOffset - 1);
    287                     UpdateLayout();
    288                     next = gen.ContainerFromIndex(itemIndex - 1);
    289                 }
    290             }
    291             while (depth != 0)
    292             {
    293                 next = VisualTreeHelper.GetChild(next, 0);
    294                 depth--;
    295             }
    296             (next as UIElement).Focus();
    297         }
    298 
    299         private void NavigateRight()
    300         {
    301             var gen = _generator.GetItemContainerGeneratorForPanel(this);
    302             UIElement selected = (UIElement)Keyboard.FocusedElement;
    303             int itemIndex = gen.IndexFromContainer(selected);
    304             int depth = 0;
    305             while (itemIndex == -1)
    306             {
    307                 selected = (UIElement)VisualTreeHelper.GetParent(selected);
    308                 itemIndex = gen.IndexFromContainer(selected);
    309                 depth++;
    310             }
    311             DependencyObject next = null;
    312             if (Orientation == Orientation.Vertical)
    313             {
    314                 int nextIndex = GetNextSectionClosestIndex(itemIndex);
    315                 next = gen.ContainerFromIndex(nextIndex);
    316                 while (next == null)
    317                 {
    318                     SetHorizontalOffset(HorizontalOffset + 1);
    319                     UpdateLayout();
    320                     next = gen.ContainerFromIndex(nextIndex);
    321                 }
    322             }
    323             else
    324             {
    325                 if (itemIndex == _abstractPanel._itemCount - 1)
    326                     return;
    327                 next = gen.ContainerFromIndex(itemIndex + 1);
    328                 while (next == null)
    329                 {
    330                     SetVerticalOffset(VerticalOffset + 1);
    331                     UpdateLayout();
    332                     next = gen.ContainerFromIndex(itemIndex + 1);
    333                 }
    334             }
    335             while (depth != 0)
    336             {
    337                 next = VisualTreeHelper.GetChild(next, 0);
    338                 depth--;
    339             }
    340             (next as UIElement).Focus();
    341         }
    342 
    343         private void NavigateUp()
    344         {
    345             var gen = _generator.GetItemContainerGeneratorForPanel(this);
    346             UIElement selected = (UIElement)Keyboard.FocusedElement;
    347             int itemIndex = gen.IndexFromContainer(selected);
    348             int depth = 0;
    349             while (itemIndex == -1)
    350             {
    351                 selected = (UIElement)VisualTreeHelper.GetParent(selected);
    352                 itemIndex = gen.IndexFromContainer(selected);
    353                 depth++;
    354             }
    355             DependencyObject next = null;
    356             if (Orientation == Orientation.Horizontal)
    357             {
    358                 int nextIndex = GetLastSectionClosestIndex(itemIndex);
    359                 next = gen.ContainerFromIndex(nextIndex);
    360                 while (next == null)
    361                 {
    362                     SetVerticalOffset(VerticalOffset - 1);
    363                     UpdateLayout();
    364                     next = gen.ContainerFromIndex(nextIndex);
    365                 }
    366             }
    367             else
    368             {
    369                 if (itemIndex == 0)
    370                     return;
    371                 next = gen.ContainerFromIndex(itemIndex - 1);
    372                 while (next == null)
    373                 {
    374                     SetHorizontalOffset(HorizontalOffset - 1);
    375                     UpdateLayout();
    376                     next = gen.ContainerFromIndex(itemIndex - 1);
    377                 }
    378             }
    379             while (depth != 0)
    380             {
    381                 next = VisualTreeHelper.GetChild(next, 0);
    382                 depth--;
    383             }
    384             (next as UIElement).Focus();
    385         }
    386 
    387 
    388         #endregion
    389 
    390         #region Override
    391 
    392         protected override void OnKeyDown(KeyEventArgs e)
    393         {
    394             switch (e.Key)
    395             {
    396                 case Key.Down:
    397                     NavigateDown();
    398                     e.Handled = true;
    399                     break;
    400                 case Key.Left:
    401                     NavigateLeft();
    402                     e.Handled = true;
    403                     break;
    404                 case Key.Right:
    405                     NavigateRight();
    406                     e.Handled = true;
    407                     break;
    408                 case Key.Up:
    409                     NavigateUp();
    410                     e.Handled = true;
    411                     break;
    412                 default:
    413                     base.OnKeyDown(e);
    414                     break;
    415             }
    416         }
    417 
    418 
    419         protected override void OnItemsChanged(object sender, ItemsChangedEventArgs args)
    420         {
    421             base.OnItemsChanged(sender, args);
    422             _abstractPanel = null;
    423             ResetScrollInfo();
    424         }
    425 
    426         protected override void OnInitialized(EventArgs e)
    427         {
    428             this.SizeChanged += new SizeChangedEventHandler(this.Resizing);
    429             base.OnInitialized(e);
    430             _itemsControl = ItemsControl.GetItemsOwner(this);
    431             _children = InternalChildren;
    432             _generator = ItemContainerGenerator;
    433         }
    434 
    435         protected override Size MeasureOverride(Size availableSize)
    436         {
    437             if (_itemsControl == null || _itemsControl.Items.Count == 0)
    438                 return availableSize;
    439             if (_abstractPanel == null)
    440                 _abstractPanel = new WrapPanelAbstraction(_itemsControl.Items.Count);
    441 
    442             _pixelMeasuredViewport = availableSize;
    443 
    444             _realizedChildLayout.Clear();
    445 
    446             Size realizedFrameSize = availableSize;
    447 
    448             int itemCount = _itemsControl.Items.Count;
    449             int firstVisibleIndex = GetFirstVisibleIndex();
    450 
    451             GeneratorPosition startPos = _generator.GeneratorPositionFromIndex(firstVisibleIndex);
    452 
    453             int childIndex = (startPos.Offset == 0) ? startPos.Index : startPos.Index + 1;
    454             int current = firstVisibleIndex;
    455             int visibleSections = 1;
    456             using (_generator.StartAt(startPos, GeneratorDirection.Forward, true))
    457             {
    458                 bool stop = false;
    459                 bool isHorizontal = Orientation == Orientation.Horizontal;
    460                 double currentX = 0;
    461                 double currentY = 0;
    462                 double maxItemSize = 0;
    463                 int currentSection = GetFirstVisibleSection();
    464                 while (current < itemCount)
    465                 {
    466                     bool newlyRealized;
    467 
    468                     // Get or create the child                    
    469                     UIElement child = _generator.GenerateNext(out newlyRealized) as UIElement;
    470                     if (newlyRealized)
    471                     {
    472                         // Figure out if we need to insert the child at the end or somewhere in the middle
    473                         if (childIndex >= _children.Count)
    474                         {
    475                             base.AddInternalChild(child);
    476                         }
    477                         else
    478                         {
    479                             base.InsertInternalChild(childIndex, child);
    480                         }
    481                         _generator.PrepareItemContainer(child);
    482                         child.Measure(ChildSlotSize);
    483                     }
    484                     else
    485                     {
    486                         // The child has already been created, let's be sure it's in the right spot
    487                         Debug.Assert(child == _children[childIndex], "Wrong child was generated");
    488                     }
    489                     childSize = child.DesiredSize;
    490                     Rect childRect = new Rect(new Point(currentX, currentY), childSize);
    491                     if (isHorizontal)
    492                     {
    493                         maxItemSize = Math.Max(maxItemSize, childRect.Height);
    494                         if (childRect.Right > realizedFrameSize.Width) //wrap to a new line
    495                         {
    496                             currentY = currentY + maxItemSize;
    497                             currentX = 0;
    498                             maxItemSize = childRect.Height;
    499                             childRect.X = currentX;
    500                             childRect.Y = currentY;
    501                             currentSection++;
    502                             visibleSections++;
    503                         }
    504                         if (currentY > realizedFrameSize.Height)
    505                             stop = true;
    506                         currentX = childRect.Right;
    507                     }
    508                     else
    509                     {
    510                         maxItemSize = Math.Max(maxItemSize, childRect.Width);
    511                         if (childRect.Bottom > realizedFrameSize.Height) //wrap to a new column
    512                         {
    513                             currentX = currentX + maxItemSize;
    514                             currentY = 0;
    515                             maxItemSize = childRect.Width;
    516                             childRect.X = currentX;
    517                             childRect.Y = currentY;
    518                             currentSection++;
    519                             visibleSections++;
    520                         }
    521                         if (currentX > realizedFrameSize.Width)
    522                             stop = true;
    523                         currentY = childRect.Bottom;
    524                     }
    525                     _realizedChildLayout.Add(child, childRect);
    526                     _abstractPanel.SetItemSection(current, currentSection);
    527 
    528                     if (stop)
    529                         break;
    530                     current++;
    531                     childIndex++;
    532                 }
    533             }
    534             CleanUpItems(firstVisibleIndex, current - 1);
    535 
    536             ComputeExtentAndViewport(availableSize, visibleSections);
    537 
    538             return availableSize;
    539         }
    540         protected override Size ArrangeOverride(Size finalSize)
    541         {
    542             if (_children != null)
    543             {
    544                 foreach (UIElement child in _children)
    545                 {
    546                     var layoutInfo = _realizedChildLayout[child];
    547                     child.Arrange(layoutInfo);
    548                 }
    549             }
    550             return finalSize;
    551         }
    552 
    553         #endregion
    554 
    555         #region IScrollInfo Members
    556 
    557         private bool _canHScroll = false;
    558         public bool CanHorizontallyScroll
    559         {
    560             get { return _canHScroll; }
    561             set { _canHScroll = value; }
    562         }
    563 
    564         private bool _canVScroll = false;
    565         public bool CanVerticallyScroll
    566         {
    567             get { return _canVScroll; }
    568             set { _canVScroll = value; }
    569         }
    570 
    571         public double ExtentHeight
    572         {
    573             get { return _extent.Height; }
    574         }
    575 
    576         public double ExtentWidth
    577         {
    578             get { return _extent.Width; }
    579         }
    580 
    581         public double HorizontalOffset
    582         {
    583             get { return _offset.X; }
    584         }
    585 
    586         public double VerticalOffset
    587         {
    588             get { return _offset.Y; }
    589         }
    590 
    591         public void LineDown()
    592         {
    593             if (Orientation == Orientation.Vertical)
    594                 SetVerticalOffset(VerticalOffset + 20);
    595             else
    596                 SetVerticalOffset(VerticalOffset + 1);
    597         }
    598 
    599         public void LineLeft()
    600         {
    601             if (Orientation == Orientation.Horizontal)
    602                 SetHorizontalOffset(HorizontalOffset - 20);
    603             else
    604                 SetHorizontalOffset(HorizontalOffset - 1);
    605         }
    606 
    607         public void LineRight()
    608         {
    609             if (Orientation == Orientation.Horizontal)
    610                 SetHorizontalOffset(HorizontalOffset + 20);
    611             else
    612                 SetHorizontalOffset(HorizontalOffset + 1);
    613         }
    614 
    615         public void LineUp()
    616         {
    617             if (Orientation == Orientation.Vertical)
    618                 SetVerticalOffset(VerticalOffset - 20);
    619             else
    620                 SetVerticalOffset(VerticalOffset - 1);
    621         }
    622 
    623         public Rect MakeVisible(Visual visual, Rect rectangle)
    624         {
    625             var gen = (ItemContainerGenerator)_generator.GetItemContainerGeneratorForPanel(this);
    626             var element = (UIElement)visual;
    627             int itemIndex = gen.IndexFromContainer(element);
    628             while (itemIndex == -1)
    629             {
    630                 element = (UIElement)VisualTreeHelper.GetParent(element);
    631                 itemIndex = gen.IndexFromContainer(element);
    632             }
    633             int section = _abstractPanel[itemIndex].Section;
    634             Rect elementRect = _realizedChildLayout[element];
    635             if (Orientation == Orientation.Horizontal)
    636             {
    637                 double viewportHeight = _pixelMeasuredViewport.Height;
    638                 if (elementRect.Bottom > viewportHeight)
    639                     _offset.Y += 1;
    640                 else if (elementRect.Top < 0)
    641                     _offset.Y -= 1;
    642             }
    643             else
    644             {
    645                 double viewportWidth = _pixelMeasuredViewport.Width;
    646                 if (elementRect.Right > viewportWidth)
    647                     _offset.X += 1;
    648                 else if (elementRect.Left < 0)
    649                     _offset.X -= 1;
    650             }
    651             InvalidateMeasure();
    652             return elementRect;
    653         }
    654 
    655         public void MouseWheelDown()
    656         {
    657             PageDown();
    658         }
    659 
    660         public void MouseWheelLeft()
    661         {
    662             PageLeft();
    663         }
    664 
    665         public void MouseWheelRight()
    666         {
    667             PageRight();
    668         }
    669 
    670         public void MouseWheelUp()
    671         {
    672             PageUp();
    673         }
    674 
    675         public void PageDown()
    676         {
    677             SetVerticalOffset(VerticalOffset + _viewport.Height * 0.8);
    678         }
    679 
    680         public void PageLeft()
    681         {
    682             SetHorizontalOffset(HorizontalOffset - _viewport.Width * 0.8);
    683         }
    684 
    685         public void PageRight()
    686         {
    687             SetHorizontalOffset(HorizontalOffset + _viewport.Width * 0.8);
    688         }
    689 
    690         public void PageUp()
    691         {
    692             SetVerticalOffset(VerticalOffset - _viewport.Height * 0.8);
    693         }
    694 
    695         private ScrollViewer _owner;
    696         public ScrollViewer ScrollOwner
    697         {
    698             get { return _owner; }
    699             set { _owner = value; }
    700         }
    701 
    702         public void SetHorizontalOffset(double offset)
    703         {
    704             if (offset < 0 || _viewport.Width >= _extent.Width)
    705             {
    706                 offset = 0;
    707             }
    708             else
    709             {
    710                 if (offset + _viewport.Width >= _extent.Width)
    711                 {
    712                     offset = _extent.Width - _viewport.Width;
    713                 }
    714             }
    715 
    716             _offset.X = offset;
    717 
    718             if (_owner != null)
    719                 _owner.InvalidateScrollInfo();
    720 
    721             InvalidateMeasure();
    722             firstIndex = GetFirstVisibleIndex();
    723         }
    724 
    725         public void SetVerticalOffset(double offset)
    726         {
    727             if (offset < 0 || _viewport.Height >= _extent.Height)
    728             {
    729                 offset = 0;
    730             }
    731             else
    732             {
    733                 if (offset + _viewport.Height >= _extent.Height)
    734                 {
    735                     offset = _extent.Height - _viewport.Height;
    736                 }
    737             }
    738 
    739             _offset.Y = offset;
    740 
    741             if (_owner != null)
    742                 _owner.InvalidateScrollInfo();
    743 
    744             //_trans.Y = -offset;
    745 
    746             InvalidateMeasure();
    747             firstIndex = GetFirstVisibleIndex();
    748         }
    749 
    750         public double ViewportHeight
    751         {
    752             get { return _viewport.Height; }
    753         }
    754 
    755         public double ViewportWidth
    756         {
    757             get { return _viewport.Width; }
    758         }
    759 
    760         #endregion
    761 
    762         #region helper data structures
    763 
    764         class ItemAbstraction
    765         {
    766             public ItemAbstraction(WrapPanelAbstraction panel, int index)
    767             {
    768                 _panel = panel;
    769                 _index = index;
    770             }
    771 
    772             WrapPanelAbstraction _panel;
    773 
    774             public readonly int _index;
    775 
    776             int _sectionIndex = -1;
    777             public int SectionIndex
    778             {
    779                 get
    780                 {
    781                     if (_sectionIndex == -1)
    782                     {
    783                         return _index % _panel._averageItemsPerSection - 1;
    784                     }
    785                     return _sectionIndex;
    786                 }
    787                 set
    788                 {
    789                     if (_sectionIndex == -1)
    790                         _sectionIndex = value;
    791                 }
    792             }
    793 
    794             int _section = -1;
    795             public int Section
    796             {
    797                 get
    798                 {
    799                     if (_section == -1)
    800                     {
    801                         return _index / _panel._averageItemsPerSection;
    802                     }
    803                     return _section;
    804                 }
    805                 set
    806                 {
    807                     if (_section == -1)
    808                         _section = value;
    809                 }
    810             }
    811         }
    812 
    813         class WrapPanelAbstraction : IEnumerable<ItemAbstraction>
    814         {
    815             public WrapPanelAbstraction(int itemCount)
    816             {
    817                 List<ItemAbstraction> items = new List<ItemAbstraction>(itemCount);
    818                 for (int i = 0; i < itemCount; i++)
    819                 {
    820                     ItemAbstraction item = new ItemAbstraction(this, i);
    821                     items.Add(item);
    822                 }
    823 
    824                 Items = new ReadOnlyCollection<ItemAbstraction>(items);
    825                 _averageItemsPerSection = itemCount;
    826                 _itemCount = itemCount;
    827             }
    828 
    829             public readonly int _itemCount;
    830             public int _averageItemsPerSection;
    831             private int _currentSetSection = -1;
    832             private int _currentSetItemIndex = -1;
    833             private int _itemsInCurrentSecction = 0;
    834             private object _syncRoot = new object();
    835 
    836             public int SectionCount
    837             {
    838                 get
    839                 {
    840                     int ret = _currentSetSection + 1;
    841                     if (_currentSetItemIndex + 1 < Items.Count)
    842                     {
    843                         int itemsLeft = Items.Count - _currentSetItemIndex;
    844                         ret += itemsLeft / _averageItemsPerSection + 1;
    845                     }
    846                     return ret;
    847                 }
    848             }
    849 
    850             private ReadOnlyCollection<ItemAbstraction> Items { get; set; }
    851 
    852             public void SetItemSection(int index, int section)
    853             {
    854                 lock (_syncRoot)
    855                 {
    856                     if (section <= _currentSetSection + 1 && index == _currentSetItemIndex + 1)
    857                     {
    858                         _currentSetItemIndex++;
    859                         Items[index].Section = section;
    860                         if (section == _currentSetSection + 1)
    861                         {
    862                             _currentSetSection = section;
    863                             if (section > 0)
    864                             {
    865                                 _averageItemsPerSection = (index) / (section);
    866                             }
    867                             _itemsInCurrentSecction = 1;
    868                         }
    869                         else
    870                             _itemsInCurrentSecction++;
    871                         Items[index].SectionIndex = _itemsInCurrentSecction - 1;
    872                     }
    873                 }
    874             }
    875 
    876             public ItemAbstraction this[int index]
    877             {
    878                 get { return Items[index]; }
    879             }
    880 
    881             #region IEnumerable<ItemAbstraction> Members
    882 
    883             public IEnumerator<ItemAbstraction> GetEnumerator()
    884             {
    885                 return Items.GetEnumerator();
    886             }
    887 
    888             #endregion
    889 
    890             #region IEnumerable Members
    891 
    892             System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
    893             {
    894                 return GetEnumerator();
    895             }
    896 
    897             #endregion
    898         }
    899 
    900         #endregion
    901     }
    902 }
  • 相关阅读:
    韩寒做错了(update 4 12)。
    放弃IE6。
    阿弥陀佛,我没有“抄袭”。
    婚姻。
    爆牙齿饭否?
    地震之后——和妈妈对话。
    8年前,《西班牙,我为你哭泣。》
    在等决赛中提问。
    地震之后——中国互联网在黑夜中哭泣。
    年轻。
  • 原文地址:https://www.cnblogs.com/xuling-297769461/p/12768982.html
Copyright © 2011-2022 走看看