Search code examples
c#wpfscrollviewplatform-specific

XAML Nested ScrollView leaves scrolling to parent


I have an app with a structure like this (where the Frame has the contents set to a Page eg MyPage:

MainWindow.xaml

<Window ... Height="450" Width="800">
    <Grid>
        <ScrollViewer VerticalScrollBarVisibility="Auto">
            <Frame NavigationUIVisibility="Hidden" Source="Page1.xaml"/>
        </ScrollViewer>
    </Grid>
</Window>

MyPage.xaml

<Page ...>
    <Grid Background="GhostWhite">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="300"/>
            <ColumnDefinition Width="*"/>
        </Grid.ColumnDefinitions>
        <Grid Background="Pink">
            <Grid.RowDefinitions>
                <RowDefinition Height="Auto"/>
                <RowDefinition Height="*"/>
            </Grid.RowDefinitions>
            <TextBlock Grid.Row="0">Title</TextBlock>
            <ScrollViewer Grid.Row="1" Background="Yellow" VerticalScrollBarVisibility="Auto">
                <StackPanel>
                    <Rectangle Margin="10" Fill="Red" Width="250" Height="100"/>
                    <Rectangle Margin="10" Fill="Red" Width="250" Height="100"/>
                    <Rectangle Margin="10" Fill="Red" Width="250" Height="100"/>
                    <Rectangle Margin="10" Fill="Red" Width="250" Height="100"/>
                </StackPanel>
            </ScrollViewer>
        </Grid>
    </Grid>
</Page>

Which in visual studio, the page renders like this, with the scrollbar inside the left panel, which is what I want it to look like:

Page preview

However, what actually ends up happening when I compile is is the page's ScrollViewis expanding to take up all the space of its contents, and the ScrollViewfrom the main window is the one that is showing the scrollbar. Like this:

enter image description here

How can I get the inner ScrollView to not grow past its parent grid?

I know I could give it a fixed height, but that isn't what I want, and I have tried wrapping the ScrollView in a Grid and binding the height of the ScrollViewto the that Grid's Height and ActualHeight properties, as well as to the same properties of the RowDefinition of the parent Grid


Solution

  • Looks like I've found a solution. I realized that in order to limit the side panel height and have it always visible, I would have to make sure the page never got bigger than the frame. To do that I had to bind the height of the root Grid to the ScrollView's ViewportHeight property. I already had a property in the MyPage class which was the frame (used for navigating purposes) like this:

    MyPage.xaml.cs

    public partial class MyPage : Page {
        public Frame Frame { get; }
        // ...
    }
    

    So in the XAML I was able to bind the height like this:

    MyPage.xaml

    <Page ...>
        <Grid Height="{Binding Frame.Parent.ViewportHeight}">
            <!-- ... -->
        </Grid>
    </Page>