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 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 );
    }