2010-08-15 5 views
11

मुझे कुछ विकल्प मिल गए हैं, this CodePlex project और this commercial one, लेकिन पूर्व मेरे परीक्षण में बेहद अक्षम है, और बाद में, $$ की लागत है। मुझे this implementation भी मिला है, लेकिन यह "टाइलपैनल" के रूप में एक रैपपैनल नहीं है, और स्वचालित रूप से आकार वाले आइटम का समर्थन नहीं करता है (हालांकि यह तेज़ प्रतीत होता है)।क्या कोई (अच्छा/मुफ्त) वर्चुअलाइजिंग WrapPanel WPF के लिए उपलब्ध है?

मुझे अपने खुद के here लिखने के बारे में कुछ "संकेत" भी मिले हैं, लेकिन डेवलपर ने इसे कंपनी के समय पर विकसित किया है, इसलिए वह अपना पूरा स्रोत पोस्ट नहीं कर सका।

क्या किसी ने एक सभ्य वर्चुअलाइजिंगप्रैपनल को लागू करने के लिए समय निकाला है और इसे सार्वजनिक रूप से पोस्ट किया है, या क्या मुझे एक दिन लेना होगा और अपना खुद का लिखना होगा?

+2

"एक दिन लेने के लिए और अपने खुद के बारे में": इस सवाल का जवाब हाल ही में के लिए, और यह है कि क्या मैं के साथ खत्म हो, आशा है कि यह मदद करता है मुझे डर है कि यह एक दिन से अधिक लेने के लिए एक साथ आने के लिए होगा संतोषजनक परिणाम ... बीटीडब्ल्यू, आप उपयोगकर्ता पर इस सुझाव के लिए मतदान कर सकते हैं वॉयस: http://dotnet.uservoice.com/forums/40583-wpf-feature-suggestions/suggestions/499455-create-a-virtualizingwrappanel –

+0

वर्चुअलाइजिंगस्टैक पैनेल भी धीमा है? –

+0

@lukas नहीं, मुझे वर्चुअलाइजिंगस्टैकपैनल काफी कुशल लगता है। – devios1

उत्तर

1

हम कुछ सफलता के साथ इस एक का इस्तेमाल किया है: http://virtualwrappanel.codeplex.com

संग्रह से आइटम निकालने के साथ कोई समस्या नहीं है, लेकिन यदि आप एक छोटे कोड ट्वीक साथ इसका समाधान नहीं कर सकते हैं: http://virtualwrappanel.codeplex.com/workitem/1

+0

और वह छोटा ट्वीक है ...? वर्कटाइम अब और नहीं है, और मुझे लगता है कि यह अभी भी आइटम हटाने पर दुर्घटनाग्रस्त है :) –

+0

ऐसा लगता है कि उन्होंने परियोजना पर अपना मुद्दा हटा दिया है ... क्षमा करें मेरे पास अब इस कोड पर संदर्भित कोड नहीं है। –

5

मैं मांग कर रहा है

using System; 
using System.Collections.Generic; 
using System.ComponentModel; 
using System.Windows; 
using System.Windows.Controls; 
using System.Windows.Controls.Primitives; 
using System.Windows.Media; 

namespace Wpf.Controls 
{ 
    // class from: https://github.com/samueldjack/VirtualCollection/blob/master/VirtualCollection/VirtualCollection/VirtualizingWrapPanel.cs 
    // MakeVisible() method from: http://www.switchonthecode.com/tutorials/wpf-tutorial-implementing-iscrollinfo 
    public class VirtualizingWrapPanel : VirtualizingPanel, IScrollInfo 
    { 
     private const double ScrollLineAmount = 16.0; 

     private Size _extentSize; 
     private Size _viewportSize; 
     private Point _offset; 
     private ItemsControl _itemsControl; 
     private readonly Dictionary<UIElement, Rect> _childLayouts = new Dictionary<UIElement, Rect>(); 

     public static readonly DependencyProperty ItemWidthProperty = 
      DependencyProperty.Register("ItemWidth", typeof(double), typeof(VirtualizingWrapPanel), new PropertyMetadata(1.0, HandleItemDimensionChanged)); 

     public static readonly DependencyProperty ItemHeightProperty = 
      DependencyProperty.Register("ItemHeight", typeof(double), typeof(VirtualizingWrapPanel), new PropertyMetadata(1.0, HandleItemDimensionChanged)); 

     private static readonly DependencyProperty VirtualItemIndexProperty = 
      DependencyProperty.RegisterAttached("VirtualItemIndex", typeof(int), typeof(VirtualizingWrapPanel), new PropertyMetadata(-1)); 
     private IRecyclingItemContainerGenerator _itemsGenerator; 

     private bool _isInMeasure; 

     private static int GetVirtualItemIndex(DependencyObject obj) 
     { 
      return (int)obj.GetValue(VirtualItemIndexProperty); 
     } 

     private static void SetVirtualItemIndex(DependencyObject obj, int value) 
     { 
      obj.SetValue(VirtualItemIndexProperty, value); 
     } 

     public double ItemHeight 
     { 
      get { return (double)GetValue(ItemHeightProperty); } 
      set { SetValue(ItemHeightProperty, value); } 
     } 

     public double ItemWidth 
     { 
      get { return (double)GetValue(ItemWidthProperty); } 
      set { SetValue(ItemWidthProperty, value); } 
     } 

     public VirtualizingWrapPanel() 
     { 
      if (!DesignerProperties.GetIsInDesignMode(this)) 
      { 
       Dispatcher.BeginInvoke((Action)Initialize); 
      } 
     } 

     private void Initialize() 
     { 
      _itemsControl = ItemsControl.GetItemsOwner(this); 
      _itemsGenerator = (IRecyclingItemContainerGenerator)ItemContainerGenerator; 

      InvalidateMeasure(); 
     } 

     protected override void OnItemsChanged(object sender, ItemsChangedEventArgs args) 
     { 
      base.OnItemsChanged(sender, args); 

      InvalidateMeasure(); 
     } 

     protected override Size MeasureOverride(Size availableSize) 
     { 
      if (_itemsControl == null) 
      { 
       return availableSize; 
      } 

      _isInMeasure = true; 
      _childLayouts.Clear(); 

      var extentInfo = GetExtentInfo(availableSize, ItemHeight); 

      EnsureScrollOffsetIsWithinConstrains(extentInfo); 

      var layoutInfo = GetLayoutInfo(availableSize, ItemHeight, extentInfo); 

      RecycleItems(layoutInfo); 

      // Determine where the first item is in relation to previously realized items 
      var generatorStartPosition = _itemsGenerator.GeneratorPositionFromIndex(layoutInfo.FirstRealizedItemIndex); 

      var visualIndex = 0; 

      var currentX = layoutInfo.FirstRealizedItemLeft; 
      var currentY = layoutInfo.FirstRealizedLineTop; 

      using (_itemsGenerator.StartAt(generatorStartPosition, GeneratorDirection.Forward, true)) 
      { 
       for (var itemIndex = layoutInfo.FirstRealizedItemIndex; itemIndex <= layoutInfo.LastRealizedItemIndex; itemIndex++, visualIndex++) 
       { 
        bool newlyRealized; 

        var child = (UIElement)_itemsGenerator.GenerateNext(out newlyRealized); 
        SetVirtualItemIndex(child, itemIndex); 

        if (newlyRealized) 
        { 
         InsertInternalChild(visualIndex, child); 
        } 
        else 
        { 
         // check if item needs to be moved into a new position in the Children collection 
         if (visualIndex < Children.Count) 
         { 
          if (Children[visualIndex] != child) 
          { 
           var childCurrentIndex = Children.IndexOf(child); 

           if (childCurrentIndex >= 0) 
           { 
            RemoveInternalChildRange(childCurrentIndex, 1); 
           } 

           InsertInternalChild(visualIndex, child); 
          } 
         } 
         else 
         { 
          // we know that the child can't already be in the children collection 
          // because we've been inserting children in correct visualIndex order, 
          // and this child has a visualIndex greater than the Children.Count 
          AddInternalChild(child); 
         } 
        } 

        // only prepare the item once it has been added to the visual tree 
        _itemsGenerator.PrepareItemContainer(child); 

        child.Measure(new Size(ItemWidth, ItemHeight)); 

        _childLayouts.Add(child, new Rect(currentX, currentY, ItemWidth, ItemHeight)); 

        if (currentX + ItemWidth * 2 >= availableSize.Width) 
        { 
         // wrap to a new line 
         currentY += ItemHeight; 
         currentX = 0; 
        } 
        else 
        { 
         currentX += ItemWidth; 
        } 
       } 
      } 

      RemoveRedundantChildren(); 
      UpdateScrollInfo(availableSize, extentInfo); 

      var desiredSize = new Size(double.IsInfinity(availableSize.Width) ? 0 : availableSize.Width, 
             double.IsInfinity(availableSize.Height) ? 0 : availableSize.Height); 

      _isInMeasure = false; 

      return desiredSize; 
     } 

     private void EnsureScrollOffsetIsWithinConstrains(ExtentInfo extentInfo) 
     { 
      _offset.Y = Clamp(_offset.Y, 0, extentInfo.MaxVerticalOffset); 
     } 

     private void RecycleItems(ItemLayoutInfo layoutInfo) 
     { 
      foreach (UIElement child in Children) 
      { 
       var virtualItemIndex = GetVirtualItemIndex(child); 

       if (virtualItemIndex < layoutInfo.FirstRealizedItemIndex || virtualItemIndex > layoutInfo.LastRealizedItemIndex) 
       { 
        var generatorPosition = _itemsGenerator.GeneratorPositionFromIndex(virtualItemIndex); 
        if (generatorPosition.Index >= 0) 
        { 
         _itemsGenerator.Recycle(generatorPosition, 1); 
        } 
       } 

       SetVirtualItemIndex(child, -1); 
      } 
     } 

     protected override Size ArrangeOverride(Size finalSize) 
     { 
      foreach (UIElement child in Children) 
      { 
       child.Arrange(_childLayouts[child]); 
      } 

      return finalSize; 
     } 

     private void UpdateScrollInfo(Size availableSize, ExtentInfo extentInfo) 
     { 
      _viewportSize = availableSize; 
      _extentSize = new Size(availableSize.Width, extentInfo.ExtentHeight); 

      InvalidateScrollInfo(); 
     } 

     private void RemoveRedundantChildren() 
     { 
      // iterate backwards through the child collection because we're going to be 
      // removing items from it 
      for (var i = Children.Count - 1; i >= 0; i--) 
      { 
       var child = Children[i]; 

       // if the virtual item index is -1, this indicates 
       // it is a recycled item that hasn't been reused this time round 
       if (GetVirtualItemIndex(child) == -1) 
       { 
        RemoveInternalChildRange(i, 1); 
       } 
      } 
     } 

     private ItemLayoutInfo GetLayoutInfo(Size availableSize, double itemHeight, ExtentInfo extentInfo) 
     { 
      if (_itemsControl == null) 
      { 
       return new ItemLayoutInfo(); 
      } 

      // we need to ensure that there is one realized item prior to the first visible item, and one after the last visible item, 
      // so that keyboard navigation works properly. For example, when focus is on the first visible item, and the user 
      // navigates up, the ListBox selects the previous item, and the scrolls that into view - and this triggers the loading of the rest of the items 
      // in that row 

      var firstVisibleLine = (int)Math.Floor(VerticalOffset/itemHeight); 

      var firstRealizedIndex = Math.Max(extentInfo.ItemsPerLine * firstVisibleLine - 1, 0); 
      var firstRealizedItemLeft = firstRealizedIndex % extentInfo.ItemsPerLine * ItemWidth - HorizontalOffset; 
      var firstRealizedItemTop = (firstRealizedIndex/extentInfo.ItemsPerLine) * itemHeight - VerticalOffset; 

      var firstCompleteLineTop = (firstVisibleLine == 0 ? firstRealizedItemTop : firstRealizedItemTop + ItemHeight); 
      var completeRealizedLines = (int)Math.Ceiling((availableSize.Height - firstCompleteLineTop)/itemHeight); 

      var lastRealizedIndex = Math.Min(firstRealizedIndex + completeRealizedLines * extentInfo.ItemsPerLine + 2, _itemsControl.Items.Count - 1); 

      return new ItemLayoutInfo 
      { 
       FirstRealizedItemIndex = firstRealizedIndex, 
       FirstRealizedItemLeft = firstRealizedItemLeft, 
       FirstRealizedLineTop = firstRealizedItemTop, 
       LastRealizedItemIndex = lastRealizedIndex, 
      }; 
     } 

     private ExtentInfo GetExtentInfo(Size viewPortSize, double itemHeight) 
     { 
      if (_itemsControl == null) 
      { 
       return new ExtentInfo(); 
      } 

      var itemsPerLine = Math.Max((int)Math.Floor(viewPortSize.Width/ItemWidth), 1); 
      var totalLines = (int)Math.Ceiling((double)_itemsControl.Items.Count/itemsPerLine); 
      var extentHeight = Math.Max(totalLines * ItemHeight, viewPortSize.Height); 

      return new ExtentInfo 
      { 
       ItemsPerLine = itemsPerLine, 
       TotalLines = totalLines, 
       ExtentHeight = extentHeight, 
       MaxVerticalOffset = extentHeight - viewPortSize.Height, 
      }; 
     } 

     public void LineUp() 
     { 
      SetVerticalOffset(VerticalOffset - ScrollLineAmount); 
     } 

     public void LineDown() 
     { 
      SetVerticalOffset(VerticalOffset + ScrollLineAmount); 
     } 

     public void LineLeft() 
     { 
      SetHorizontalOffset(HorizontalOffset + ScrollLineAmount); 
     } 

     public void LineRight() 
     { 
      SetHorizontalOffset(HorizontalOffset - ScrollLineAmount); 
     } 

     public void PageUp() 
     { 
      SetVerticalOffset(VerticalOffset - ViewportHeight); 
     } 

     public void PageDown() 
     { 
      SetVerticalOffset(VerticalOffset + ViewportHeight); 
     } 

     public void PageLeft() 
     { 
      SetHorizontalOffset(HorizontalOffset + ItemWidth); 
     } 

     public void PageRight() 
     { 
      SetHorizontalOffset(HorizontalOffset - ItemWidth); 
     } 

     public void MouseWheelUp() 
     { 
      SetVerticalOffset(VerticalOffset - ScrollLineAmount * SystemParameters.WheelScrollLines); 
     } 

     public void MouseWheelDown() 
     { 
      SetVerticalOffset(VerticalOffset + ScrollLineAmount * SystemParameters.WheelScrollLines); 
     } 

     public void MouseWheelLeft() 
     { 
      SetHorizontalOffset(HorizontalOffset - ScrollLineAmount * SystemParameters.WheelScrollLines); 
     } 

     public void MouseWheelRight() 
     { 
      SetHorizontalOffset(HorizontalOffset + ScrollLineAmount * SystemParameters.WheelScrollLines); 
     } 

     public void SetHorizontalOffset(double offset) 
     { 
      if (_isInMeasure) 
      { 
       return; 
      } 

      offset = Clamp(offset, 0, ExtentWidth - ViewportWidth); 
      _offset = new Point(offset, _offset.Y); 

      InvalidateScrollInfo(); 
      InvalidateMeasure(); 
     } 

     public void SetVerticalOffset(double offset) 
     { 
      if (_isInMeasure) 
      { 
       return; 
      } 

      offset = Clamp(offset, 0, ExtentHeight - ViewportHeight); 
      _offset = new Point(_offset.X, offset); 

      InvalidateScrollInfo(); 
      InvalidateMeasure(); 
     } 

     public Rect MakeVisible(Visual visual, Rect rectangle) 
     { 
      if (rectangle.IsEmpty || 
       visual == null || 
       visual == this || 
       !IsAncestorOf(visual)) 
      { 
       return Rect.Empty; 
      } 

      rectangle = visual.TransformToAncestor(this).TransformBounds(rectangle); 

      var viewRect = new Rect(HorizontalOffset, VerticalOffset, ViewportWidth, ViewportHeight); 
      rectangle.X += viewRect.X; 
      rectangle.Y += viewRect.Y; 

      viewRect.X = CalculateNewScrollOffset(viewRect.Left, viewRect.Right, rectangle.Left, rectangle.Right); 
      viewRect.Y = CalculateNewScrollOffset(viewRect.Top, viewRect.Bottom, rectangle.Top, rectangle.Bottom); 

      SetHorizontalOffset(viewRect.X); 
      SetVerticalOffset(viewRect.Y); 
      rectangle.Intersect(viewRect); 

      rectangle.X -= viewRect.X; 
      rectangle.Y -= viewRect.Y; 

      return rectangle; 
     } 

     private static double CalculateNewScrollOffset(double topView, double bottomView, double topChild, double bottomChild) 
     { 
      var offBottom = topChild < topView && bottomChild < bottomView; 
      var offTop = bottomChild > bottomView && topChild > topView; 
      var tooLarge = (bottomChild - topChild) > (bottomView - topView); 

      if (!offBottom && !offTop) 
       return topView; 

      if ((offBottom && !tooLarge) || (offTop && tooLarge)) 
       return topChild; 

      return bottomChild - (bottomView - topView); 
     } 


     public ItemLayoutInfo GetVisibleItemsRange() 
     { 
      return GetLayoutInfo(_viewportSize, ItemHeight, GetExtentInfo(_viewportSize, ItemHeight)); 
     } 

     public bool CanVerticallyScroll 
     { 
      get; 
      set; 
     } 

     public bool CanHorizontallyScroll 
     { 
      get; 
      set; 
     } 

     public double ExtentWidth 
     { 
      get { return _extentSize.Width; } 
     } 

     public double ExtentHeight 
     { 
      get { return _extentSize.Height; } 
     } 

     public double ViewportWidth 
     { 
      get { return _viewportSize.Width; } 
     } 

     public double ViewportHeight 
     { 
      get { return _viewportSize.Height; } 
     } 

     public double HorizontalOffset 
     { 
      get { return _offset.X; } 
     } 

     public double VerticalOffset 
     { 
      get { return _offset.Y; } 
     } 

     public ScrollViewer ScrollOwner 
     { 
      get; 
      set; 
     } 

     private void InvalidateScrollInfo() 
     { 
      if (ScrollOwner != null) 
      { 
       ScrollOwner.InvalidateScrollInfo(); 
      } 
     } 

     private static void HandleItemDimensionChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 
     { 
      var wrapPanel = (d as VirtualizingWrapPanel); 

      if (wrapPanel != null) 
       wrapPanel.InvalidateMeasure(); 
     } 

     private double Clamp(double value, double min, double max) 
     { 
      return Math.Min(Math.Max(value, min), max); 
     } 

     internal class ExtentInfo 
     { 
      public int ItemsPerLine; 
      public int TotalLines; 
      public double ExtentHeight; 
      public double MaxVerticalOffset; 
     } 

     public class ItemLayoutInfo 
     { 
      public int FirstRealizedItemIndex; 
      public double FirstRealizedLineTop; 
      public double FirstRealizedItemLeft; 
      public int LastRealizedItemIndex; 
     } 
    } 
} 
+0

अरे धन्यवाद आदमी, यह मेरे उद्देश्य के लिए एक आकर्षण की तरह काम कर रहा है – jdehaan

+2

यह नियंत्रण केवल तभी काम करता है जब आप समय से पहले जानते हैं कि प्रत्येक पैनल की चौड़ाई और ऊंचाई क्या है। यह 'वर्चुअलाइजिंग ट्रिपपेनल' की तुलना में 'वर्चुअलाइजिंग टाइलपैनेल' से अधिक है। –

संबंधित मुद्दे