0
votes

My user control doesn't seem to obey HorizontalAlignment or VerticalAlignment during the layout process.

I have a Windows Store XAML User Control defined as follows:

<UserControl
    x:Class="IWalker.Views.PDFPageUserControl"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:IWalker.Views"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    d:DesignHeight="200"
    d:DesignWidth="250">

    <Image x:Name="ThumbImage"/>

</UserControl>

It is in an ItemsControl horizontal list as follows (I've dropped the Page XAML decl at the top for brevity - but it is from the Windows Store blank template):

<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
    <ScrollViewer VerticalScrollMode="Disabled" HorizontalScrollMode="Auto" VerticalScrollBarVisibility="Disabled" HorizontalScrollBarVisibility="Auto">
        <ItemsControl x:Name="SlideStrip">
            <ItemsControl.ItemsPanel>
                <ItemsPanelTemplate>
                    <StackPanel Orientation="Horizontal"/>
                </ItemsPanelTemplate>
            </ItemsControl.ItemsPanel>
            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <local:PDFPageUserControl Margin="0 0 5 0" Height="{Binding Path=ActualHeight, ElementName=SlideStrip, Mode=OneWay}" ViewModel="{Binding}" RespectRenderingDimension="Vertical" />
                </DataTemplate>
            </ItemsControl.ItemTemplate>
        </ItemsControl>
    </ScrollViewer>
</Grid>

As you can see, PDFPageUserControl has its Height bound to the ActualHeight of the ItemsControl it is going to be sitting in. When this happens, everything works just fine. If I remove that binding, then my user control is size 0,0.

Here is the tricky part. The PDFPageUserControl doesn't have an implicit size. I need to set either its Height, Width, or both (as you can see it doing in the above code snippit). It will then use the PDF rendering code to generate an image of the correct size and display it (all this works).

My theory of what is going on is that Windows Store XAML's auto layout, by default, doesn't try to expand things till they fit. It lets most controls determine their own size and report that to the layout engine. Then the layout engine does the layout around them, building up. Mine reports it is 0,0 initially, waiting to be told its height so it can inform the system of its width or vice versa. Since the ItemsControl's StackPannel never forces the items to stretch to fit its interior, that doesn't happen.

However, it is obvious that some controls are allowed to expand to fill all available space - like the Grid or the ScrollViewer here. I had thought that the "Stretch" mode for Horizontal and Vertical alignment would do this for you in the layout engine. But that doesn't seem to work for my UserControl - as if I am not properly participating in the layout process.

Is there a way to fix my control so it will stretch to fill available space as ordered by HorizontalAlignment and VerticalAlignment?

If you feel there is some basic missing info/code here, ask, of course, and I'll add it. You can also see all the code here: https://github.com/gordonwatts/IndicoWalker/tree/master/IWalker/IWalker.Windows/Views

2

2 Answers

1
votes

ActualHeight in WinRT/XAML isn't bindable - it doesn't raise change notifications, so you should update it manually. Consider my DoubleViewModel answer to this question:

GridView with 2 columns, fill width

1
votes

It turns out the key to this particular problem is to participate in the layout engine's process. In particular, the user control should override the MeasureOverride method. When that is done, I can drop the Height binding in the XAML above.

MeasureOverride will tell you the available size, which will depend on things like the VerticalAlignment and HorizontalAlignment. Depending, some suggested sizes will be reasonable numbers, and others will be NaN. I could then calculate the size of my image, and hand it back.

That done, the Layout engine would then resize my UserControl. I hooked into the SizeChanged event, and each time I saw that, I re-generate my image. The resulting code is quite clean!

One word of caution for those new at this - make sure to be ready for NaN values to come in for the available size.