The GridView control is one of the most used layout controls within Windows 8 Store applications. By using the Grid App project template with Visual Studio 2012, your first page will look similar to the following:
While this looks great, what if you’d like to create a items that vary in size? Something like the following:
This type of layout is possible using the GridView with very little extra work. There are multiple methods for accomplishing this task; some easier than others, some with more code than Xaml.
One way would be to subclass the GridView control and put in the necessary plumbing. See Jerry Nixon’s post.
Another way would be to follow Andrej Torzon’s advice using attached properties, reflection and a binding helper.
My solution, however, was to minimize the extra code by using the capabilities already present in the GridView. To get started, the first thing to do is to tell the GridView to use a VariableSizedWrapGrid. You do that by adding as follows:
Step 1 is to create a new ItemsPanelTemplate for the GridView (I like to create separate resources, but this could be embedded in the GridView Xaml itself).
<ItemsPanelTemplate x:Key="VariableSizedItemTemplate"> <VariableSizedWrapGrid Orientation="Vertical" /> </ItemsPanelTemplate>
Step 2 requires the default Style for the GridViewItem control, which you can find here, or extract using a tool like Expression Blend. If there is a way to base a new style off of an implicit one, I haven’t found it. Once you have the defined style, turn it into an explicit style by giving it a Key. I am using the following snippet:
<Style x:Key="DefaultGridViewItemStyle" TargetType="GridViewItem">
...
</Style>
Step 3 involves creating Styles for each of the new sizes you want to incorporate into your GridView. Ideally, the best way would be to use multiples of the single cell size from an aesthetics point of view. To create the new sizes, simply create some new Styles based on the base GridViewItem style. For the purposes of demonstration, I’m creating two sizes, normal and double-height. So all I need is the double height style, and I can create it easily by just basing it on the previous DefaultGridViewStyle:
<Style x:Key="DoubleHeightGridViewItemStyle" BasedOn="{StaticResource DefaultGridViewItemStyle}" TargetType="GridViewItem"> <Setter Property="VariableSizedWrapGrid.RowSpan" Value="2" /> </Style>
Remember the width and height of the default cell size is determined by your ItemTemplate, so we’re just specifying spans for the GridViewItems.
Step 4 requires writing a little bit of custom code. We need to create an ItemContainerStyleSelector. This will allow the GridView to pick one of the two Styles we just created. The code is quite simple, but can grow in complexity as the number of differently sized items grows.
public class VariableSizedStyleSelector : StyleSelector { public Style NormalStyle { get; set;
public Style DoubleHeightStyle { get; set; }
protected override Style SelectStyleCore(object item, DependencyObject container) { if (this.NormalStyle == null || this.DoubleHeightStyle == null) return base.SelectStyleCore(item, container);
if (item is INormalItem)
return NormalStyle;
if (item is ISpecialItem)
return DoubleHeightStyle;
return base.SelectStyleCore(item, container);
} }
My decision logic is a bit contrived, but the point is that you can insert any algorithm to determine which style to use. I could have just as easily picked a property on the item and based my logic off that instead.
In Step 5, we need to create a resource in our Xaml to use the new StyleSelector.
<local:VariableSizedStyleSelector x:Key="VariableSizedStyleSelector" NormalStyle="{StaticResource DefaultGridViewItemStyle}" DoubleHeightStyle="{StaticResource DoubleHeightGridViewItemStyle}" />
Finally, have your GridView use both the VariableSizedItemTemplate by setting its ItemPanel property, and the VariableSizedStyleSelector by setting its ItemContainerStyleSelector property.
<GridView x:Name="ItemGridView" ...
ItemsSource="{Binding Source={StaticResource ItemsViewSource}}" ItemTemplateSelector="{StaticResource CustomItemTemplateSelector}" ItemsPanel="{StaticResource VariableSizedItemTemplate}" ItemContainerStyleSelector="{StaticResource VariableSizedStyleSelector}"> </GridView>
I’ve included the ItemTemplateSelector property in the Xaml snippet above to show how you would change the actual appearance of the ItemTemplate itself. That is, if your double-height item requires a substantially different template than your default ItemTemplate, you would have to follow a process similar to the one that created the VariableSizedStyleSelector class, but inherit from DataTemplateSelector instead.
I hope this helps, and provides you another tool for creating variable-sized GridView layouts.