1

I'm trying to allow vertical scrolling on a list of settings, using an ItemsControl inside of a ScrollViewer. The scrolling works when I set the Height of the ScrollViewer to a constant like 400, but stops working when I set the height to auto or set the VerticalAlignment to stretch.

Here's my code

<ScrollViewer VerticalAlignment="Stretch" >
    <ItemsControl ItemsSource="{x:Bind _settingsViewModel.Settings}"
                      ItemTemplate="{StaticResource SettingTemplate}"/>
</ScrollViewer>

How can I set the Height of the ScrollViewer to fit the size of the screen but still allow scrolling?

Edit: I should also mention that my page exists as a content page inside of a NavigationView.

Here is everything inside my navigation view:

<StackPanel>
    <breadcrumb:BreadcrumbControl
      x:Name="breadcrumbTrail"
      DisplayMemberPath="Title"
      HomeText="Home"
      Seperator="/"
      OverFlow="..."
      HomeSelected="breadcrumbTrail_HomeSelected"
      />

    <Frame x:Name="ContentFrame" Margin="24" Navigated="Frame_Navigated">
        <Frame.ContentTransitions>
            <TransitionCollection>
                <NavigationThemeTransition/>
            </TransitionCollection>
        </Frame.ContentTransitions>
    </Frame>
</StackPanel>
James Hogle
  • 3,010
  • 3
  • 22
  • 46
Caleb Powell
  • 150
  • 7

2 Answers2

0

The problem is that you need to cap the dimension the ScrollViewer object can occupy!

<Grid.RowDefinitions>
    <RowDefinition Height="*"/>
    <RowDefinition Height="Auto"/>
    <RowDefinition Height="*"/>
</Grid.RowDefinitions>

So what did we define above?

  • Defined a parent layout container of type Grid.
  • The Grid layout container has 3 rows, with the middle row taking as much space as required, while the first and last will have the real estate leftovers divided equally between them.

Now we decide to define the ScrollViewer inside the middle row.

This is a problem! You have defined your ScrollViewer inside a row which will define it's height according to the content that it holds. This definitely goes against the concept of a ScrollViewer! How can you scroll something, if you are setting it to take as much space as required to hold all of its children? Even if the size doesn't go "over" the screen size, it will still not be possible to actually scroll through anything since you have not set a maximum height for the ScrollViewer, and therefore all the content can actually be displayed without any scrolling at all. The problem can get even worse, when the content inside the ScrollViewer occupies so much real estate, that it will eat all the space you would want to have for the other layout areas. And in this worse situation, it is still not possible to scroll through anything, despite existing layout which is not being shown to us ...

How can we resolve this? Either by setting the MaxHeight dependency property of your ScrollViewer, as you have already done, or by changing the definition of the layout container.

Now, I will simply set the middle row to have 2* times the size of the other 2 rows (now there exists a limitation on the size of the ScrollViewer):

<Grid.RowDefinitions>
    <RowDefinition Height="*"/>
    <RowDefinition Height="2*"/>
    <RowDefinition Height="*"/>
</Grid.RowDefinitions>

Now we can simply define the ScrollViewer as part of the middle row, like this:

<ScrollViewer Grid.Row="1" ...> 

If the content insides it occupies more than the calculate *2** size, you will see the ScrollViewer scrolling in action, just like you want to!


Just as a minor suggestion, I generally like to define some of the Attached Properties defined in the ScrollViewer class, such as the ScrollViewer.VerticalScrollBarVisibility and the ScrollViewer.VerticalScrollMode in the definition of the object (for focused the horizontal scroll behavior, we have the same logic but for the attached properties HorizontalScrollMode and HorizontalScrollBarVisibility)

In this case I would define them as Attributes of the ScrollViewer, rather than an attached property defined in the children of the ScrollViewer, simply because it becomes easier to understand the developer intentions and i prefer the Auto definition for the ScrollMode behavior.

<ScrollViewer Grid.Row="1" 
              VerticalScrollBarVisibility="Visible" 
              VerticalScrollMode="Auto"> ... </ScrollViewer>
André B
  • 1,699
  • 2
  • 11
  • 22
0

According to this post a ScrollView cannot exist inside of a stack panel without directly setting the height of the of the ScrollView. Since this ScrollView exists inside of a Frame that is nested inside of a StackPanel you will run into the issue described.

You could use a Grid instead of a StackPanel to achieve the effect you are looking for.

<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="25"/>
        <RowDefinition Height="*"/>
    </Grid.RowDefinitions>

      <breadcrumb:BreadcrumbControl
      x:Name="breadcrumbTrail"
      DisplayMemberPath="Title"
      HomeText="Home"
      Seperator="/"
      OverFlow="..."
      HomeSelected="breadcrumbTrail_HomeSelected"
      Grid.Row="0"
      />

    <Frame x:Name="ContentFrame" Margin="24" Navigated="Frame_Navigated" Grid.Row="1">
        <Frame.ContentTransitions>
            <TransitionCollection>
                <NavigationThemeTransition/>
            </TransitionCollection>
        </Frame.ContentTransitions>
    </Frame>
</Grid>
James Hogle
  • 3,010
  • 3
  • 22
  • 46