none
ScrollViewer with non scrolling area (fixed header)

    Question

  • How can I have a ScrollViewer with a fixed header (like the Column headers in a GridView).

    <ScrollViewer>
      <
    StackPanel>
        <
    Label Content="Header" />
        ...Some content...

      </StackPanel>
    </
    ScrollViewer>

    Best regards,
    Thomas Andersen

    Wednesday, September 13, 2006 11:19 AM

All replies

  • You can retrofit HeaderedContentControl to meet your own needs:
    <Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
               xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        >
      <Page.Resources>
        <ControlTemplate TargetType="HeaderedContentControl" x:Key="myControlTemplate">
          <StackPanel>
            <ContentPresenter
                ContentSource="Header"
                ContentTemplate="{TemplateBinding HeaderedContentControl.HeaderTemplate}"
                Content="{TemplateBinding HeaderedContentControl.Header}"/>
            <ScrollViewer ContentTemplate="{TemplateBinding ContentControl.ContentTemplate}"
                Content="{TemplateBinding ContentControl.Content}"/>
          </StackPanel>
        </ControlTemplate>
      </Page.Resources>
      <HeaderedContentControl Header="HeaderText" Template="{StaticResource myControlTemplate}">
        <!--Put your content here-->
      </HeaderedContentControl>
    </Page>

    Sheva
    Wednesday, September 13, 2006 12:10 PM
  • Thanks.

    Actually I forgot to mention an important part: The header is a GridViewHeaderRowPresenter witch I want to follow the horizontal scrolling?

    Best regards,
      Thomas Andersen

     

    Wednesday, September 13, 2006 2:25 PM
  • Thought I would post a solution - as this prooved a little problematic and noone else seemed to have a solution posted anywhere.

    The trick is (maybe there are better solutions too) to wrap the header and content in a scrollviewer to allow horizontal scrolling and then to wrap the content items in a scrollviewer to allow vertical scrolling of the items.

    The sample XAML below is for the TreeListView sample in MSDN.

    The problem still remains that the inner scrollviewer can create a vertical scrollbar off-screen - whereas it would be nice to have it right-docked.

    <Style TargetType="{x:Type l:TreeListView}">

    <Setter Property="OverridesDefaultStyle" Value="True" />

    <Setter Property="Template">

    <Setter.Value>

    <ControlTemplate TargetType="{x:Type l:TreeListView}">

    <Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}">

    <DockPanel Dock="Top" HorizontalAlignment="Stretch">

    <ScrollViewer Focusable="False" CanContentScroll="False" Padding="4" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Disabled">

    <DockPanel Dock="Top" VerticalAlignment="Stretch">

    <GridViewHeaderRowPresenter Columns="{StaticResource gvcc}" ColumnHeaderContainerStyle="{StaticResource driverRowHeaderStyle}" DockPanel.Dock="Top">

    </GridViewHeaderRowPresenter>

    <ScrollViewer HorizontalScrollBarVisibility="Hidden"

    VerticalScrollBarVisibility="Auto"

    Focusable="False" VerticalAlignment="Stretch" CanContentScroll="False" Padding="4">

    <ItemsPresenter VerticalAlignment="Stretch"/>

    </ScrollViewer>

    </DockPanel>

    </ScrollViewer>

    </DockPanel>

    </Border>

    </ControlTemplate>

    </Setter.Value>

    </Setter>

    </Style>

     

     

    Wednesday, December 20, 2006 10:57 AM
  • Does anyone know how to solve the vertical scrollbar off-screen problem?
    Wednesday, November 18, 2009 5:15 PM
  • To solve the vertical scrollbar off-screen problem, use two ScrollView instances.  Put the GridViewHeaderRowPresenter in its own ScrollView with hidden scrollbars.  Put the ItemsPresenter in a second ScrollView with both scrollbars enabled.  When the second ScrollView ScrollChanged event is fired, set the first ScrollView horizontal offset to match.

      <Style TargetType="{x:Type l:TreeListView}">
        <Setter Property="OverridesDefaultStyle" Value="True" />
        <Setter Property="Template">
          <Setter.Value>
            <ControlTemplate TargetType="{x:Type l:TreeListView}">
              <Border 
                BorderBrush="{TemplateBinding BorderBrush}" 
                BorderThickness="{TemplateBinding BorderThickness}">
                <DockPanel Dock="Top" HorizontalAlignment="Stretch">
                  <DockPanel Dock="Top" VerticalAlignment="Stretch">
                    <ScrollViewer 
                      Name="ScrollViewer_Header"
                      DockPanel.Dock="Top"
                      HorizontalAlignment="Left"
                      HorizontalScrollBarVisibility="Hidden" 
                      VerticalScrollBarVisibility="Disabled">
                      <GridViewHeaderRowPresenter 
                        Columns="{StaticResource gvcc}" 
                        ColumnHeaderContainerStyle="{StaticResource driverRowHeaderStyle}"/>
                    </ScrollViewer>
                    <ScrollViewer 
                      Name="ScrollViewer_Body"
                      HorizontalScrollBarVisibility="Auto"
                      VerticalScrollBarVisibility="Auto">
                      <ItemsPresenter/>
                    </ScrollViewer>
                  </DockPanel>
                </DockPanel>
              </Border>
            </ControlTemplate>
          </Setter.Value>
        </Setter>
      </Style>
    
    

     

    class TreeListView : TreeView
    {
      ScrollViewer ScrollViewer_Header;
      ScrollViewer ScrollViewer_Body;
    
      public override void OnApplyTemplate()
      {
        base.OnApplyTemplate();
    
        this.ScrollViewer_Header = (ScrollViewer)this.Template.FindName("ScrollViewer_Header", this);
        this.ScrollViewer_Body = (ScrollViewer)this.Template.FindName("ScrollViewer_Body", this);
    
        this.ScrollViewer_Body.ScrollChanged += new ScrollChangedEventHandler(ScrollViewer_Body_ScrollChanged);
      }
    
      void ScrollViewer_Body_ScrollChanged(object sender, ScrollChangedEventArgs e)
      {
        this.ScrollViewer_Header.Width = e.ViewportWidth;
        this.ScrollViewer_Header.ScrollToHorizontalOffset(e.HorizontalOffset);
      }
    }
    
    

    • Proposed as answer by LeeCampbell Wednesday, March 07, 2012 4:44 PM
    Tuesday, March 08, 2011 1:34 PM
  • Cheers Ian,

    I was banging my head on that one for a while trying to use only Binding. The private setters make that impossible however. Your ScrollToHorizontalOffset(e.HorizontalOffset); worked a treat. Thanks.


    Lee Campbell http://LeeCampbell.blogspot.com

    Wednesday, March 07, 2012 4:46 PM