Windows RT XAML Controls - GridWrap Column autosizing to window size

323 views Asked by At

I have been looking for a resizeable Universal Windows App (RT, UWP) control for handling different screen sizes and scalable controls. What I am looking for is something like a wrapgrid (What I am using below), except that it changes the column width to fill the space when it is resized, like what occurs with the Tubecast app for windows, when you resize the window the columns will expand, or when shrinking, merge once they hit a minimum value.

Currently I am using a wrapgrid control to fill the TV shows into the library, adding a new frame in code, navigating it to a new instance of the LibraryModel Page, passing a class via the onNavigatedTo() method. This XAML page has a min properties of 135x200, and a max properties of 270x400, using static item height and with of 270x400 and visual state groups to change to 125x200 when the width goes below 720px. I tried using a variablesizedwrapgrid, but it wasn't any more helpful.

Is there a control like this that exists for UWP apps? Or will it need to be created manually using C#, or added to the platform later? This control is likely essential for future Windows 10 App development. Example Screenshot

2

There are 2 answers

0
William Bradley On BEST ANSWER

I figured out a way to make the controls scale to screen sizes, so that they will take up all available real estate, and works well on all devices.

UltraWide Others shown at bottom of page..

<Grid Background="#FF1D1D1D" x:Name="maingrid" SizeChanged="maingrid_SizeChanged">

    <Grid Grid.ColumnSpan="2" Grid.RowSpan="2">
        <ScrollViewer x:Name="LibraryScroll">
            <Grid>
                <Viewbox x:Name="LibraryItemViewbox" Stretch="Uniform" VerticalAlignment="Top" HorizontalAlignment="Left">
                    <Grid x:Name="Area" Width="{x:Bind maingrid.Width}" Height="{x:Bind maingrid.Height}">
                        <ItemsControl x:Name="showsPanel" Loaded="showsPanel_Loaded" ItemsSource="{x:Bind Library.LibraryItems, Mode=OneWay}">
                            <ItemsControl.ItemsPanel>
                                <ItemsPanelTemplate>
                                    <WrapGrid x:Name="shows" Orientation="Horizontal" ItemHeight="400" ItemWidth="270" MaximumRowsOrColumns="3"/>
                                </ItemsPanelTemplate>
                            </ItemsControl.ItemsPanel>
                            <ItemsControl.ItemTemplate>
                                <DataTemplate x:DataType="viewmodel:LibraryItemModel">
                                    <Button Padding="0" Foreground="Transparent" BorderThickness="0" Tapped="LibraryItem_Tapped" RightTapped="LibraryItem_RightTapped" Holding="Button_Holding"/>
                                        <Grid x:Name="MainGrid" Background="#00A6A6A6" Width="270" Height="400">
                                            <!-- Content -->
                                        </Grid>
                                    </Button>
                                </DataTemplate>
                            </ItemsControl.ItemTemplate>
                        </ItemsControl>
                    </Grid>
                </Viewbox>
            </Grid>
        </ScrollViewer>
    </Grid>
</Grid>

This is the XAML structure required to scale the content. The Viewbox is wrapped into a Grid, so that Vertical and Horizontal Alignment still works inside the ScrollViewer. The inner Grid "Area" has its Height and Width bound to the base Grid 'maingrid', so it maintains the aspect ratio of the page.

The Itemscontrol is defined as a WrapGrid, meaning that Item Width has to be defined, meaning this won't work variable sized controls inside (Although possible with some modification). The ItemTemplate is then defined as well (Requiring the Base Grid 'MainGrid' to be the same dimensions as the WrapGrid's ItemWidth and ItemHeight).

Events that are required are SizeChanged on the Base Grid and Loaded on the ItemsControl.

In order to scale the elements when the page is loaded, and scale them when the page is resized, the code looks like this:

    private void showsPanel_Loaded(object sender, RoutedEventArgs e)
    {
        Area.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
        Resize();
        fillGaps(showsPanel.ItemsPanelRoot as WrapGrid);
    }

    private void Resize()
    {
        var width = this.ActualWidth;
        var height = this.ActualHeight;
        var grid = (WrapGrid)showsPanel.ItemsPanelRoot;
        int numofColsOrig = grid.MaximumRowsOrColumns;
        if (width >= 2800) grid.MaximumRowsOrColumns = 8;
        if (width < 2800) grid.MaximumRowsOrColumns = 8;
        if (width < 2400) grid.MaximumRowsOrColumns = 7;
        if (width < 2000) grid.MaximumRowsOrColumns = 6;
        if (width < 1600) grid.MaximumRowsOrColumns = 5;
        if (width < 1200) grid.MaximumRowsOrColumns = 4;
        if (width < 800) grid.MaximumRowsOrColumns = 3;
        if (width < 400)
        {
            grid.MaximumRowsOrColumns = 2;
            if (Library.LibraryItems.Count >= 2) Area.Padding = new Thickness(0);
        }

        if (numofColsOrig != grid.MaximumRowsOrColumns)
        {
            fillGaps(grid);
        }
    }

    private void fillGaps(WrapGrid grid)
    {
        var libraryitems = Library.LibraryItems;
        if (libraryitems.Count < grid.MaximumRowsOrColumns && libraryitems.Count != 0)
        {
            int numOfItemsToFill = grid.MaximumRowsOrColumns - libraryitems.Count;
            Area.Padding = new Thickness { Right = (grid.ItemWidth * numOfItemsToFill) };
        }
    }

    private void maingrid_SizeChanged(object sender, SizeChangedEventArgs e) { Resize(); }

The values of widths to change the number of rows will need to be manually tweaked in order to look better with different size objects, and when adding or removing from the ItemSource, Resize(); will have to be called to recalculate the dimensions of the elements, for it to look correct.

You will, of course, need to replace libraryitems with you own ObservableCollection, so that it can get the count of how many objects are in your list, or get the count from your WrapGrid's items count.

Regular Mobile

0
eZ_Harry On

I suggest you look at view-boxes, might provide a solution.