53c8d6d934
- Aggiunta lista lastre che scorre e gestisce migliaia di lastre. - Miglioramenti e correzioni varie.
296 lines
11 KiB
VB.net
296 lines
11 KiB
VB.net
Imports System.Windows.Controls.Primitives
|
|
Imports System.Windows.Controls
|
|
Imports System.Windows
|
|
Imports System.Windows.Media
|
|
Imports System
|
|
Imports System.Diagnostics
|
|
Imports System.Collections.Specialized
|
|
Imports System.Windows.Data
|
|
|
|
Public Class VirtualizingTilePanel
|
|
Inherits VirtualizingPanel
|
|
Implements IScrollInfo
|
|
|
|
Public Sub New()
|
|
' For use in the IScrollInfo implementation
|
|
Me.RenderTransform = _trans
|
|
End Sub
|
|
|
|
Public Shared ReadOnly ChildSizeProperty As DependencyProperty = DependencyProperty.RegisterAttached("ChildSize", GetType(Double), GetType(VirtualizingTilePanel), New FrameworkPropertyMetadata(200.0, FrameworkPropertyMetadataOptions.AffectsMeasure Or FrameworkPropertyMetadataOptions.AffectsArrange))
|
|
|
|
Public Property ChildSize As Double
|
|
Get
|
|
Return CDbl(GetValue(ChildSizeProperty))
|
|
End Get
|
|
Set(ByVal value As Double)
|
|
SetValue(ChildSizeProperty, value)
|
|
End Set
|
|
End Property
|
|
|
|
Protected Overrides Function MeasureOverride(ByVal availableSize As Size) As Size
|
|
UpdateScrollInfo(availableSize)
|
|
Dim firstVisibleItemIndex, lastVisibleItemIndex As Integer
|
|
GetVisibleRange(firstVisibleItemIndex, lastVisibleItemIndex)
|
|
Dim children As UIElementCollection = Me.InternalChildren
|
|
Dim generator As IItemContainerGenerator = Me.ItemContainerGenerator
|
|
Dim startPos As GeneratorPosition = generator.GeneratorPositionFromIndex(firstVisibleItemIndex)
|
|
Dim childIndex As Integer = If((startPos.Offset = 0), startPos.Index, startPos.Index + 1)
|
|
Using generator.StartAt(startPos, GeneratorDirection.Forward, True)
|
|
Dim itemIndex As Integer = firstVisibleItemIndex
|
|
While itemIndex <= lastVisibleItemIndex
|
|
Dim newlyRealized As Boolean
|
|
Dim child As UIElement = TryCast(generator.GenerateNext(newlyRealized), UIElement)
|
|
If newlyRealized Then
|
|
If childIndex >= children.Count Then
|
|
MyBase.AddInternalChild(child)
|
|
Else
|
|
MyBase.InsertInternalChild(childIndex, child)
|
|
End If
|
|
generator.PrepareItemContainer(child)
|
|
Else
|
|
Debug.Assert(child Is children(childIndex), "Wrong child was generated")
|
|
End If
|
|
|
|
child.Measure(GetChildSize())
|
|
System.Threading.Interlocked.Increment(itemIndex)
|
|
System.Threading.Interlocked.Increment(childIndex)
|
|
End While
|
|
End Using
|
|
|
|
CleanUpItems(firstVisibleItemIndex, lastVisibleItemIndex)
|
|
Return availableSize
|
|
End Function
|
|
|
|
Protected Overrides Function ArrangeOverride(ByVal finalSize As Size) As Size
|
|
Dim generator As IItemContainerGenerator = Me.ItemContainerGenerator
|
|
UpdateScrollInfo(finalSize)
|
|
For i As Integer = 0 To Me.Children.Count - 1
|
|
Dim child As UIElement = Me.Children(i)
|
|
Dim itemIndex As Integer = generator.IndexFromGeneratorPosition(New GeneratorPosition(i, 0))
|
|
ArrangeChild(itemIndex, child, finalSize)
|
|
Next
|
|
|
|
Return finalSize
|
|
End Function
|
|
|
|
Private Sub CleanUpItems(ByVal minDesiredGenerated As Integer, ByVal maxDesiredGenerated As Integer)
|
|
Dim children As UIElementCollection = Me.InternalChildren
|
|
Dim generator As IItemContainerGenerator = Me.ItemContainerGenerator
|
|
Dim i As Integer = children.Count - 1
|
|
While i >= 0
|
|
Dim childGeneratorPos As GeneratorPosition = New GeneratorPosition(i, 0)
|
|
Dim itemIndex As Integer = generator.IndexFromGeneratorPosition(childGeneratorPos)
|
|
If itemIndex < minDesiredGenerated OrElse itemIndex > maxDesiredGenerated Then
|
|
generator.Remove(childGeneratorPos, 1)
|
|
RemoveInternalChildRange(i, 1)
|
|
End If
|
|
i -= 1
|
|
End While
|
|
End Sub
|
|
|
|
Protected Overrides Sub OnItemsChanged(ByVal sender As Object, ByVal args As ItemsChangedEventArgs)
|
|
Select Case args.Action
|
|
Case NotifyCollectionChangedAction.Remove, NotifyCollectionChangedAction.Replace, NotifyCollectionChangedAction.Move
|
|
RemoveInternalChildRange(args.Position.Index, args.ItemUICount)
|
|
End Select
|
|
End Sub
|
|
|
|
Private Function CalculateExtent(ByVal availableSize As Size, ByVal itemCount As Integer) As Size
|
|
Dim childrenPerRow As Integer = CalculateChildrenPerRow(availableSize)
|
|
Return New Size(childrenPerRow * Me.ChildSize, Me.ChildSize * Math.Ceiling(CDbl(itemCount) / childrenPerRow))
|
|
End Function
|
|
|
|
Private Sub GetVisibleRange(ByRef firstVisibleItemIndex As Integer, ByRef lastVisibleItemIndex As Integer)
|
|
Dim childrenPerRow As Integer = CalculateChildrenPerRow(_extent)
|
|
firstVisibleItemIndex = CInt(Math.Floor(_offset.Y / Me.ChildSize)) * childrenPerRow
|
|
lastVisibleItemIndex = CInt(Math.Ceiling((_offset.Y + _viewport.Height) / Me.ChildSize)) * childrenPerRow - 1
|
|
Dim itemsControl As ItemsControl = itemsControl.GetItemsOwner(Me)
|
|
Dim itemCount As Integer = If(itemsControl.HasItems, itemsControl.Items.Count, 0)
|
|
If lastVisibleItemIndex >= itemCount Then lastVisibleItemIndex = itemCount - 1
|
|
End Sub
|
|
|
|
Private Function GetChildSize() As Size
|
|
Return New Size(Me.ChildSize, Me.ChildSize)
|
|
End Function
|
|
|
|
Private Sub ArrangeChild(ByVal itemIndex As Integer, ByVal child As UIElement, ByVal finalSize As Size)
|
|
Dim childrenPerRow As Integer = CalculateChildrenPerRow(finalSize)
|
|
Dim row As Integer = itemIndex \ childrenPerRow ' IMPORTANTE L'operatore è di divisione intera, quindi \ NON / che invece arrotonda all'intero pari più vicino!!!!
|
|
Dim column As Integer = itemIndex Mod childrenPerRow
|
|
child.Arrange(New Rect(column * Me.ChildSize, row * Me.ChildSize, Me.ChildSize, Me.ChildSize))
|
|
End Sub
|
|
|
|
Private Function CalculateChildrenPerRow(ByVal availableSize As Size) As Integer
|
|
Dim childrenPerRow As Integer
|
|
If availableSize.Width = Double.PositiveInfinity Then childrenPerRow = Me.Children.Count Else childrenPerRow = Math.Max(1, CInt(Math.Floor(availableSize.Width / Me.ChildSize)))
|
|
Return childrenPerRow
|
|
End Function
|
|
|
|
Private Sub UpdateScrollInfo(ByVal availableSize As Size)
|
|
Dim itemsControl As ItemsControl = itemsControl.GetItemsOwner(Me)
|
|
Dim itemCount As Integer = If(itemsControl.HasItems, itemsControl.Items.Count, 0)
|
|
Dim extent As Size = CalculateExtent(availableSize, itemCount)
|
|
If extent <> _extent Then
|
|
_extent = extent
|
|
If _owner IsNot Nothing Then _owner.InvalidateScrollInfo()
|
|
End If
|
|
|
|
If availableSize <> _viewport Then
|
|
_viewport = availableSize
|
|
If _owner IsNot Nothing Then _owner.InvalidateScrollInfo()
|
|
End If
|
|
End Sub
|
|
|
|
Public Property ScrollOwner As ScrollViewer Implements IScrollInfo.ScrollOwner
|
|
Get
|
|
Return _owner
|
|
End Get
|
|
|
|
Set(ByVal value As ScrollViewer)
|
|
_owner = value
|
|
End Set
|
|
End Property
|
|
|
|
Public Property CanHorizontallyScroll As Boolean Implements IScrollInfo.CanHorizontallyScroll
|
|
Get
|
|
Return _canHScroll
|
|
End Get
|
|
|
|
Set(ByVal value As Boolean)
|
|
_canHScroll = value
|
|
End Set
|
|
End Property
|
|
|
|
Public Property CanVerticallyScroll As Boolean Implements IScrollInfo.CanVerticallyScroll
|
|
Get
|
|
Return _canVScroll
|
|
End Get
|
|
|
|
Set(ByVal value As Boolean)
|
|
_canVScroll = value
|
|
End Set
|
|
End Property
|
|
|
|
Public ReadOnly Property HorizontalOffset As Double Implements IScrollInfo.HorizontalOffset
|
|
Get
|
|
Return _offset.X
|
|
End Get
|
|
End Property
|
|
|
|
Public ReadOnly Property VerticalOffset As Double Implements IScrollInfo.VerticalOffset
|
|
Get
|
|
Return _offset.Y
|
|
End Get
|
|
End Property
|
|
|
|
Public ReadOnly Property ExtentHeight As Double Implements IScrollInfo.ExtentHeight
|
|
Get
|
|
Return _extent.Height
|
|
End Get
|
|
End Property
|
|
|
|
Public ReadOnly Property ExtentWidth As Double Implements IScrollInfo.ExtentWidth
|
|
Get
|
|
Return _extent.Width
|
|
End Get
|
|
End Property
|
|
|
|
Public ReadOnly Property ViewportHeight As Double Implements IScrollInfo.ViewportHeight
|
|
Get
|
|
Return _viewport.Height
|
|
End Get
|
|
End Property
|
|
|
|
Public ReadOnly Property ViewportWidth As Double Implements IScrollInfo.ViewportWidth
|
|
Get
|
|
Return _viewport.Width
|
|
End Get
|
|
End Property
|
|
|
|
Public Sub LineUp() Implements IScrollInfo.LineUp
|
|
SetVerticalOffset(Me.VerticalOffset - 10)
|
|
End Sub
|
|
|
|
Public Sub LineDown() Implements IScrollInfo.LineDown
|
|
SetVerticalOffset(Me.VerticalOffset + 10)
|
|
End Sub
|
|
|
|
Public Sub PageUp() Implements IScrollInfo.PageUp
|
|
SetVerticalOffset(Me.VerticalOffset - _viewport.Height)
|
|
End Sub
|
|
|
|
Public Sub PageDown() Implements IScrollInfo.PageDown
|
|
SetVerticalOffset(Me.VerticalOffset + _viewport.Height)
|
|
End Sub
|
|
|
|
Public Sub MouseWheelUp() Implements IScrollInfo.MouseWheelUp
|
|
SetVerticalOffset(Me.VerticalOffset - 50)
|
|
End Sub
|
|
|
|
Public Sub MouseWheelDown() Implements IScrollInfo.MouseWheelDown
|
|
SetVerticalOffset(Me.VerticalOffset + 50)
|
|
End Sub
|
|
|
|
Public Sub LineLeft() Implements IScrollInfo.LineLeft
|
|
Throw New InvalidOperationException()
|
|
End Sub
|
|
|
|
Public Sub LineRight() Implements IScrollInfo.LineRight
|
|
Throw New InvalidOperationException()
|
|
End Sub
|
|
|
|
Public Function MakeVisible(ByVal visual As Visual, ByVal rectangle As Rect) As Rect Implements IScrollInfo.MakeVisible
|
|
Return New Rect()
|
|
End Function
|
|
|
|
Public Sub MouseWheelLeft() Implements IScrollInfo.MouseWheelLeft
|
|
Throw New InvalidOperationException()
|
|
End Sub
|
|
|
|
Public Sub MouseWheelRight() Implements IScrollInfo.MouseWheelRight
|
|
Throw New InvalidOperationException()
|
|
End Sub
|
|
|
|
Public Sub PageLeft() Implements IScrollInfo.PageLeft
|
|
Throw New InvalidOperationException()
|
|
End Sub
|
|
|
|
Public Sub PageRight() Implements IScrollInfo.PageRight
|
|
Throw New InvalidOperationException()
|
|
End Sub
|
|
|
|
Public Sub SetHorizontalOffset(ByVal offset As Double) Implements IScrollInfo.SetHorizontalOffset
|
|
Throw New InvalidOperationException()
|
|
End Sub
|
|
|
|
Public Sub SetVerticalOffset(ByVal offset As Double) Implements IScrollInfo.SetVerticalOffset
|
|
If offset < 0 OrElse _viewport.Height >= _extent.Height Then
|
|
offset = 0
|
|
Else
|
|
If offset + _viewport.Height >= _extent.Height Then
|
|
offset = _extent.Height - _viewport.Height
|
|
End If
|
|
End If
|
|
|
|
_offset.Y = offset
|
|
If _owner IsNot Nothing Then _owner.InvalidateScrollInfo()
|
|
_trans.Y = -offset
|
|
InvalidateMeasure()
|
|
End Sub
|
|
|
|
Private _trans As TranslateTransform = New TranslateTransform()
|
|
|
|
Private _owner As ScrollViewer
|
|
|
|
Private _canHScroll As Boolean = False
|
|
|
|
Private _canVScroll As Boolean = False
|
|
|
|
Private _extent As Size = New Size(0, 0)
|
|
|
|
Private _viewport As Size = New Size(0, 0)
|
|
|
|
Private _offset As Point
|
|
|
|
End Class
|