What a pain-in-the-ass! I need to have a combination of features that seems common, but are not supplied by Microsoft in their WinRT environment. WinRT, in case it is not clear, is the operating system API used by Windows Store apps. A Windows Store app is a Windows 8 program built using WinRT.

Anyhow, I have variable height items that I need to wrap from one column to the next. The VariableSizedWrapGrid is pretty useless because my items do not have a predictable height. The only thing predictable about them is that each is a self-contained unit. Wrapping plain text from column to column will be a problem to solve later, but for now, I am only wrapping UI elements like TextBox, or TextBlock.

I found a WrapPanel implementation at Code Project which does exactly what I need for wrapping. Thanks to Matej Pavlů for writing that.

But the tricky part is the scrolling. I can find many posts on many forums, all saying that the height of the ScrollViewer needs to be fixed for this to work. That’s ugly. Why is VerticalAlignment="Stretch" not making the height fixed once it figures out the parent height? That’s probably because the parent could change and then the fixed height would no longer be correct. But how do I get the height right. here’s the short story (code):

<common:LayoutAwarePage
    x:Name="pageRoot"
    x:Class="MyApp.FormPage"
    DataContext="{Binding DefaultViewModel, RelativeSource={RelativeSource Self}}"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:MyApp"
    xmlns:data="using:MyApp.Data"
    xmlns:common="using:MyApp.Common"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d">

    <Grid Style="{StaticResource LayoutRootStyle}" Margin="0,0,0,88">
        <Grid.RowDefinitions>
            <RowDefinition Height="140"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>

        <ScrollViewer VerticalAlignment="Top" HorizontalAlignment="Left" Grid.Row="1" Margin="0,-9,0,0" 
                         HorizontalScrollMode="Enabled" VerticalScrollMode="Disabled"
                         VerticalScrollBarVisibility="Disabled" 
                         HorizontalScrollBarVisibility="Auto">
            <Grid x:Name="itemGridView" Margin="116,0,40,46">
                <Grid>
                    <Grid.RowDefinitions>
                        <RowDefinition Height="48"/>
                        <RowDefinition Height="*"/>
                    </Grid.RowDefinitions>
                    <TextBlock Grid.Row="0" Margin="0,0,0,18" VerticalAlignment="Top" Style="{StaticResource GroupHeaderTextStyle}" 
                                  Text="Location" Height="30"/>

                    <local:WrapPanel Grid.Row="1" Background="Brown" VerticalAlignment="Stretch" HorizontalAlignment="Left"
                                        MinWidth="100" BlockSize="350" BlockSpacing="15" Orientation="Vertical">
                        <Button HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Content="Test 1" />
                        <Button HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Content="Test 2" />
                        <Button HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Content="Test 3" />
                        <Button HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Content="Test 3" />
                        <Button HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Content="Test 3" />
                        <Button HorizontalAlignment="Stretch" Height="190" Content="Test 3" />
                        <Button HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Content="Test 3" />
                        <Button HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Content="Test 3" />
                        <Button HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Content="Test 3" />
                        <Button HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Content="Test 3" />
                        <Button HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Content="Test 3" />
                        <Button HorizontalAlignment="Stretch" Height="300" Content="Test 3" />
                        <Button HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Content="Test 3" />
                        <Button HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Content="Test 3" />
                        <Button HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Content="Test 3" />
                        <Button HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Content="Test 3" />
                        <Button HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Content="Test 3" />
                        <Button HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Content="Test 4" />
                        <Button HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Content="Test 5" />
                        <Button HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Content="Test 6" />
                        <Button HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Content="Test 7" />
                        <Button HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Content="Test 3" />
                        <Button HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Content="Test 3" />
                        <Button HorizontalAlignment="Stretch" Height="100" Content="Test 3" />
                        <Button HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Content="Test 3" />
                        <Button HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Content="Test 3" />
                        <Button HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Content="Test 3" />
                    </local:WrapPanel>
                </Grid>
            </Grid>
        </ScrollViewer>

        <!-- Back button and page title -->
        <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="Auto"/>
                <ColumnDefinition Width="*"/>
            </Grid.ColumnDefinitions>
            <Button x:Name="backButton" Click="GoBack" IsEnabled="{Binding Frame.CanGoBack, ElementName=pageRoot}" 
                       Style="{StaticResource BackButtonStyle}"/>
            <TextBlock x:Name="pageTitle" Text="Test Form" Grid.Column="1" IsHitTestVisible="false" 
                          Style="{StaticResource PageHeaderTextStyle}"/>
        </Grid>

    </Grid>
</common:LayoutAwarePage>

I’m going to just point out the one mistake that took me an hour to find. Look on line 22. Note that it says VerticalScrollBarVisibility="Disabled". If VerticalScrollBarVisibility was set to "Hidden" then the ScrollViewer would have an infinite height and code inside of WrapPanel would return "infinite" from one of the measurement calculations. Don’t trust code copied fro the internet!

The infinite measurement then causes this very helpful [sarcasm] exception:

Error HRESULT E_FAIL has been returned from a call to a COM component

Finally, I now have a horizontally scrolling variable height content container:

image

Scroll Test of Variable Content Height Wrapping Container

I threw this post together rather quickly, and it may be a bit confusing. Hopefully the code will explain everything. The trick to finding this was to not assume that any attribute was set correctly. I checked everything related to height to see what options were available and that’s how I discovered the difference between "hidden" and "disabled".

Dave