[UWP] ScrollViewer and different app window heights.

Category: windows phone development

Question

BitSmithy on Fri, 23 Sep 2016 11:12:37


I have a XAML with ScrollViewer and Canvas inside it:

...

                <ScrollViewer x:Name="scvCanvas">
                    <Canvas x:Name="cnvCanvas" ScrollViewer.VerticalScrollBarVisibility="Visible" ScrollViewer.VerticalScrollMode="Enabled"/>
                </ScrollViewer>

...

Height of Canvas is setting always in code behind and often is higher then screen area, so I must put the Canvas inside ScrollViewer.

But ScrollViewer has unactive Vertical ScrollBar. The ScrollBar becomes active only if I set in XAML fixed height for the ScrollViewer.

But app can work on different screen sizes so i can't set there fixed height.

How to made ScrollBar of the ScrollViewer active if the canvas crops out bottom screen edge?


Replies

Martin Zhema on Mon, 26 Sep 2016 07:55:13


Hi BitSmithy,
I added the following code to MainPage.Xaml,
<ScrollViewer >
      <Canvas x:Name="cnvCanvas" Background="Red" ScrollViewer.VerticalScrollBarVisibility="Visible" ScrollViewer.VerticalScrollMode="Enabled"/>
</ScrollViewer>

Then I wrote cnvCanvas.Height = 900 in code behind. When I run the project, the app can show ScrollBar automatically, not as you said : The ScrollBar becomes active only if I set in XAML fixed height for the ScrollViewer.

But if you want to set different height of ScrollViewer in different app's Window, you can use VisualStateManager to do this, the following is the code, please check:

 <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}" Name="RootGrid">
        <VisualStateManager.VisualStateGroups>
            <VisualStateGroup x:Name="VisualStateGroup">
                <VisualState x:Name="Narrow">
                    <VisualState.Setters>
                        <Setter Target="RootGrid.(Height)" Value="200" />
                    </VisualState.Setters>
                    <VisualState.StateTriggers>
                        <AdaptiveTrigger MinWindowHeight="300"/>
                    </VisualState.StateTriggers>
                </VisualState>
                <VisualState x:Name="Width">
                    <VisualState.Setters>
                        <Setter Target="RootGrid.(Height)" Value="400" />
                    </VisualState.Setters>
                    <VisualState.StateTriggers>
                        <AdaptiveTrigger MinWindowHeight="600"/>
                    </VisualState.StateTriggers>
                </VisualState>
            </VisualStateGroup>
        </VisualStateManager.VisualStateGroups>


        <ScrollViewer Height="{Binding ElementName=RootGrid,Path=Height}">
            <Canvas x:Name="cnvCanvas" Background="Red" ScrollViewer.VerticalScrollBarVisibility="Visible" ScrollViewer.VerticalScrollMode="Enabled"/>
        </ScrollViewer>
    </Grid>

BitSmithy on Tue, 27 Sep 2016 15:49:00


>> Then I wrote cnvCanvas.Height = 900 in code behind. When I run the project, the app can show ScrollBar automatically, not as you said : >> The ScrollBar becomes active only if I set in XAML fixed height for the ScrollViewer.

I tested more this case. If you opaque ScrollViewer in Grid, it shows ScrollBar well. But if you opaque it in StackPanel, the ScrollBar isn't enabled. The same is, if the layout is combination of Grids and StackPanels the ScrollBar not always is enabled.

It looks like with StackPanels placed in layout, ScrollViewer extends below of my app bootom. I need to find any way to protect it from extending below my app.

Martin Zhema on Wed, 28 Sep 2016 05:15:40


Hi BitSmithy,
>>I tested more this case. If you opaque ScrollViewer in Grid, it shows ScrollBar well. But if you opaque it in StackPanel, the ScrollBar isn't enabled. The same is, if the layout is combination of Grids and StackPanels the ScrollBar not always is enabled.
To understand what's wrong with this, I have a test.
1.I tested the ScorllerView in StackPanel, the following is my code:
<Page
    x:Name="MyPage"
    x:Class="_9._26TestScrollview.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:_9._26TestScrollview"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d">
 
 
    <StackPanel Background="Black" Name="RootPanel">
        <Button Click="Button_Click" Background="Yellow">Click</Button>
        <ScrollViewer Background="Blue" Height="{Binding ElementName=RootGrid,Path=Height}">
            <Canvas x:Name="cnvCanvas" Background="Red" ScrollViewer.VerticalScrollBarVisibility="Visible" ScrollViewer.VerticalScrollMode="Enabled"/>
        </ScrollViewer>
    </StackPanel>
</Page>

public MainPage()
        {
            this.InitializeComponent();
            cnvCanvas.Height = 1000;
        }
 
        private void Button_Click(object sender, RoutedEventArgs e)
        {
            Debug.WriteLine(RootPanel.ActualHeight);
        }
Then when I click the button, the ActualHeight of RootPanel is 1032, it is out of the screen. So as you see, if I haven't given a initial size of StackPanel and if the StackPanel's content size is bigger then the screen, then the StackPanel's size depend on it's content size.
 
2. Also I tested the ScorllerView in Grid, the following is my code:
<Page
    x:Name="MyPage"
    x:Class="_9._26TestScrollview.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:_9._26TestScrollview"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d">
 
 
    <Grid Background="Black" Name="RootGrid">
        <Grid.RowDefinitions>
            <RowDefinition Height="30"></RowDefinition>
            <RowDefinition Height="*"></RowDefinition>
        </Grid.RowDefinitions>
        <Button Grid.Row="0" Click="Button_Click" Background="Yellow">Click</Button>
        <ScrollViewer Grid.Row="1" Background="Blue" Height="{Binding ElementName=RootGrid,Path=Height}">
            <Canvas x:Name="cnvCanvas" Background="Red" ScrollViewer.VerticalScrollBarVisibility="Visible" ScrollViewer.VerticalScrollMode="Enabled"/>
        </ScrollViewer>
    </Grid>
</Page>

Then I clicked the button, the ActualHeight of RootGrid is 768. That's the defference, the height of Grid does not depend on it's content size.
 
3. To solve your question, you just need to set a value of Height in StackPanel. You can use binding for this. Please check the following code:
 
<StackPanel Background="Black" Name="RootGrid" Height="{Binding ElementName=MyPage,Path=ActualHeight}">
        <Button Click="Button_Click" Background="Yellow">Click</Button>
        <ScrollViewer Background="Blue" Height="{Binding ElementName=RootGrid,Path=Height}">
            <Canvas x:Name="cnvCanvas" Background="Red" ScrollViewer.VerticalScrollBarVisibility="Visible" ScrollViewer.VerticalScrollMode="Enabled"/>
        </ScrollViewer>
    </StackPanel>
Also if you want different height of StackPanel in different Window, you can use visualStateManager in my last reply.