internal double GetStickyFootersRegionHeight( StickyContainerInfoList stickyFooters ) { int count = stickyFooters.Count; double lastStickyFooterOffset = m_viewportHeight; for( int i = 0; i < count; i++ ) { double desiredOffset = this.ComputeStickyFooterDesiredOffset( stickyFooters[ i ], lastStickyFooterOffset ); lastStickyFooterOffset = Math.Min( desiredOffset, lastStickyFooterOffset ); } return lastStickyFooterOffset; }
internal double GetStickyHeadersRegionHeight( StickyContainerInfoList stickyHeaders ) { int count = stickyHeaders.Count; double lastStickyHeaderOffset = -m_containerHeight; for( int i = 0; i < count; i++ ) { double desiredOffset = this.ComputeStickyHeaderDesiredOffset( stickyHeaders[ i ], lastStickyHeaderOffset ); lastStickyHeaderOffset = Math.Max( desiredOffset, lastStickyHeaderOffset ); } return lastStickyHeaderOffset + m_containerHeight; }
private void GenerateStickyHeaders( ICustomItemContainerGenerator generator, bool measureInvalidated, ref UIElement focusedElement ) { CustomItemContainerGenerator customGenerator = ( CustomItemContainerGenerator )generator; if( !this.AreHeadersStickyCache && !this.AreGroupHeadersStickyCache && !this.AreParentRowsStickyCache ) { this.RecycleUnusedStickyContainers( generator, m_stickyHeaders, null, ref focusedElement ); m_stickyHeaders.Clear(); return; } int numberOfContainerChecked = 0; StickyContainerInfoList newStickyHeaders = new StickyContainerInfoList(); foreach( LayoutedContainerInfo layoutedContainerInfo in m_layoutedContainers ) { UIElement container = layoutedContainerInfo.Container; // For each visible container, we must find what headers should be sticky for it. List<StickyContainerGenerated> stickyHeaders = customGenerator.GenerateStickyHeaders( container, this.AreHeadersStickyCache, this.AreGroupHeadersStickyCache, this.AreParentRowsStickyCache ); stickyHeaders.Sort( StickyContainerGeneratedComparer.Singleton ); // For each sticky headers returned, we must get the index of the last container // that could need that container to be sticky. foreach( StickyContainerGenerated stickyHeaderInfo in stickyHeaders ) { UIElement stickyContainer = ( UIElement )stickyHeaderInfo.StickyContainer; if( newStickyHeaders.ContainsContainer( stickyContainer ) ) continue; int lastContainerIndex = customGenerator.GetLastHoldingContainerIndexForStickyHeader( stickyContainer ); StickyContainerInfo stickyContainerInfo = new StickyContainerInfo( stickyContainer, stickyHeaderInfo.Index, lastContainerIndex ); newStickyHeaders.Add( stickyContainerInfo ); if( focusedElement == stickyContainer ) { focusedElement = null; } this.HandleGeneratedStickyContainerPreparation( stickyHeaderInfo, measureInvalidated ); } // We only need to find the sticky headers for one // more element than what is already sticky. int visibleStickyHeadersCount = ( int )Math.Ceiling( this.GetStickyHeadersRegionHeight( newStickyHeaders ) / m_containerHeight ); if( ( ++numberOfContainerChecked - visibleStickyHeadersCount ) >= 1 ) break; } foreach( StickyContainerInfo stickyHeaderInfo in newStickyHeaders ) { UIElement container = stickyHeaderInfo.Container; int index = m_layoutedContainers.IndexOfContainer( container ); if( index > -1 ) { m_layoutedContainers.RemoveAt( index ); } m_layoutedContainersToRecycle.Remove( container ); } this.RecycleUnusedStickyContainers( generator, m_stickyHeaders, newStickyHeaders, ref focusedElement ); m_stickyHeaders.Clear(); m_stickyHeaders.AddRange( newStickyHeaders ); m_stickyHeaders.Sort( StickyContainerInfoComparer.Singleton ); }
private void GenerateStickyFooters( ICustomItemContainerGenerator generator, bool measureInvalidated, ref UIElement focusedElement ) { if( !this.AreFootersStickyCache && !this.AreGroupFootersStickyCache ) { this.RecycleUnusedStickyContainers( generator, m_stickyFooters, null, ref focusedElement ); m_stickyFooters.Clear(); return; } CustomItemContainerGenerator customGenerator = ( CustomItemContainerGenerator )generator; int numberOfContainerChecked = 0; StickyContainerInfoList newStickyFooters = new StickyContainerInfoList(); int layoutedContainerCount = m_layoutedContainers.Count; if( layoutedContainerCount > 0 ) { // We must not generate sticky footers if the last container is not even at the bottom of the view! LayoutedContainerInfo bottomMostContainerInfo = m_layoutedContainers[ layoutedContainerCount - 1 ]; double bottomMostContainerOffset = this.GetContainerOffsetFromIndex( bottomMostContainerInfo.RealizedIndex ); if( ( bottomMostContainerOffset + m_containerHeight ) >= m_viewportHeight ) { for( int i = layoutedContainerCount - 1; i >= 0; i-- ) { LayoutedContainerInfo layoutedContainerInfo = m_layoutedContainers[ i ]; UIElement layoutedContainer = layoutedContainerInfo.Container; // For each visible container, we must find what footers should be sticky for it. List<StickyContainerGenerated> stickyFooters = customGenerator.GenerateStickyFooters( layoutedContainer, this.AreFootersStickyCache, this.AreGroupFootersStickyCache ); stickyFooters.Sort( StickyContainerGeneratedReverseComparer.Singleton ); // For each sticky headers returned, we must get the index of the last container // that could need that container to be sticky. foreach( StickyContainerGenerated stickyFooterInfo in stickyFooters ) { UIElement stickyContainer = ( UIElement )stickyFooterInfo.StickyContainer; if( newStickyFooters.ContainsContainer( stickyContainer ) ) continue; int firstContainerIndex = customGenerator.GetFirstHoldingContainerIndexForStickyFooter( stickyContainer ); StickyContainerInfo stickyContainerInfo = new StickyContainerInfo( stickyContainer, stickyFooterInfo.Index, firstContainerIndex ); newStickyFooters.Add( stickyContainerInfo ); if( focusedElement == stickyContainer ) { focusedElement = null; } this.HandleGeneratedStickyContainerPreparation( stickyFooterInfo, measureInvalidated ); } // We only need to find the sticky footers for one // more element than what is already sticky. int visibleStickyFootersCount = ( int )Math.Ceiling( ( this.AnimatedScrollInfo.ViewportHeight - this.GetStickyFootersRegionHeight( newStickyFooters ) ) / m_containerHeight ); if( ( ++numberOfContainerChecked - visibleStickyFootersCount ) >= 1 ) break; } } } foreach( StickyContainerInfo stickyFooterInfo in newStickyFooters ) { int indexOf = m_layoutedContainers.IndexOfContainer( stickyFooterInfo.Container ); if( indexOf > -1 ) { m_layoutedContainers.RemoveAt( indexOf ); } } this.RecycleUnusedStickyContainers( generator, m_stickyFooters, newStickyFooters, ref focusedElement ); m_stickyFooters.Clear(); m_stickyFooters.AddRange( newStickyFooters ); m_stickyFooters.Sort( StickyContainerInfoReverseComparer.Singleton ); }
private void RecycleUnusedStickyContainers( ICustomItemContainerGenerator generator, StickyContainerInfoList stickyContainers, StickyContainerInfoList stickyContainersToExclude, ref UIElement focusedElement ) { for( int i = stickyContainers.Count - 1; i >= 0; i-- ) { StickyContainerInfo stickyHeaderInfo = stickyContainers[ i ]; UIElement container = stickyHeaderInfo.Container; if( m_layoutedContainers.ContainsContainer( container ) ) continue; if( ( stickyContainersToExclude != null ) && ( stickyContainersToExclude.ContainsContainer( container ) ) ) continue; if( container.IsKeyboardFocusWithin ) { Debug.Assert( ( focusedElement == null ) || ( focusedElement == container ) ); focusedElement = container; continue; } int index = generator.GetRealizedIndexForContainer( container ); this.RecycleContainer( generator, index, container ); stickyContainers.RemoveAt( i ); } }