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 double ComputeStickyFooterDesiredOffset( StickyContainerInfo stickyFooterInfo, double lastStickyFooterOffset ) { double firstHoldingContainerOffset = this.GetContainerOffsetFromIndex( stickyFooterInfo.HoldingContainerIndex ) - m_verticalOffset; double desiredStickyFooterOffset = lastStickyFooterOffset - m_containerHeight; double realFooterOffset = this.GetContainerOffsetFromIndex( stickyFooterInfo.ContainerIndex ) - m_verticalOffset; desiredStickyFooterOffset = Math.Max( firstHoldingContainerOffset, desiredStickyFooterOffset ); desiredStickyFooterOffset = Math.Min( realFooterOffset, desiredStickyFooterOffset ); return desiredStickyFooterOffset; }
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 ); }