Building WinRT / Windows 8 Grouped items using MVVMLight

Tags: .NET, C#, Metro, MVVM, Visual Studio, Windows 8, WinRT, XAML

Categories: .NET, WinRT

Tags: .NET, C#, Metro, MVVM, Visual Studio, Windows 8, WinRT, XAML

One of the reasons to use MVVM pattern is the fact that you can design before having the application fully implemented. Tests are also an important part but this is not the topic of this article. When creating WinRT applications Blend is the tool you definitely should use.  When working with Grouped Items in GridView you don't have out of the box support for design using MVVM. In the following steps I will start with a new application using MvvmLight and add all the necessary bits for binding and displaying the data in UI.

In order to work with MvvmLight you need to install it. Get a copy from here MvvmLight After installation it will add an MvvmLight project to your list of projects and some MvvmLight templates to the list of templates which you can add on an already existing project.

You can download the source code of this article from GitHub Grouped Items with MvvmLight. I removed some of the code created by MvvmLight template to keep it simpler to understand. If you want to check what MvvmLight creates just a create a new MvvmLight project and check the code.
Fire Visual Studio and create a new project. This will be an MvvmLight project.


clip_image002

 

When you chose the MvvmLight project it creates a few classes. You can use other type but you'll need to add these classes manually.
First of all, the App.xaml file was updated with the following

<vm:ViewModelLocator x:Key="Locator" d:IsDataSource="True"  />

It references the ViewModelLocator class added in the ViewModel folder. This is a locator class and uses SimpleIoc as a dependency injector.

MainViewModel class was created in the same ViewModel folder and has WelcomeTitle property binded – this was created by MvvmLight and I didn’t remove it.

The MainPage.xaml updated with the DataContext reference

DataContext="{Binding Main, Source={StaticResource Locator}}

Here Main is the 'Main' property of type MainViewModel defined in the ViewModelLocator.   
We will create an example of products so for this purpose a new set of classes were added to the Model folder. The first one - ProductItem has Title, Price and images properties. The second one - ProductGroup has Title which is the title of the group and Items which is a collection of ProductItems for the same group.

The MainViewModel class had a constructor with IDataService parameter which was created by MvvmLight. That constructor is not needed any more and we need to create a constructor with no parameters. I will explain later why we need it. In the constructor I will set the WelcomeTitle and I will populate the Products collection with data.

Let's add a grid view to the MainPage

<Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
        <Grid.RowDefinitions>
            <RowDefinition Height="13*"/>
            <RowDefinition Height="51*"/>
        </Grid.RowDefinitions>
        <TextBlock FontSize="56"
                   Text="{Binding WelcomeTitle}"
                   VerticalAlignment="Top"
                   HorizontalAlignment="Left"
                   FontFamily="Segoe UI Light" 
                   Margin="120,49,0,0" />

        <Grid Style="{StaticResource LayoutRootStyle}" Grid.Row="1">

            <GridView
            x:Name="itemGridView"
            AutomationProperties.AutomationId="ItemGridView"
            AutomationProperties.Name="Grouped Items"
            Grid.RowSpan="2"
            Padding="116,1,40,46"
            ItemsSource="{Binding Source={StaticResource groupedItemsViewSource}}"
            ItemTemplate="{StaticResource Standard250x250ItemTemplate}"
            SelectionMode="None"
            IsSwipeEnabled="false">

                <GridView.ItemsPanel>
                    <ItemsPanelTemplate>
                        <VirtualizingStackPanel Orientation="Horizontal"/>
                    </ItemsPanelTemplate>
                </GridView.ItemsPanel>
                <GridView.GroupStyle>
                    <GroupStyle>
                        <GroupStyle.HeaderTemplate>
                            <DataTemplate>
                                <Grid Margin="1,0,0,6">
                                    <Button
                                    AutomationProperties.Name="Group Title"
                                    Style="{StaticResource TextPrimaryButtonStyle}">
                                        <StackPanel Orientation="Horizontal">
                                            <TextBlock Text="{Binding Title}" Margin="3,-7,10,10" Style="{StaticResource GroupHeaderTextStyle}" />
                                            <TextBlock Text="{StaticResource ChevronGlyph}" FontFamily="Segoe UI Symbol" Margin="0,-7,0,10" Style="{StaticResource GroupHeaderTextStyle}"/>
                                        </StackPanel>
                                    </Button>
                                </Grid>
                            </DataTemplate>
                        </GroupStyle.HeaderTemplate>
                        <GroupStyle.Panel>
                            <ItemsPanelTemplate>
                                <VariableSizedWrapGrid Orientation="Vertical" Margin="0,0,80,0"/>
                            </ItemsPanelTemplate>
                        </GroupStyle.Panel>
                    </GroupStyle>
                </GridView.GroupStyle>
            </GridView>
        </Grid>
</Grid>

Grid View ItemsSource is defined using groupedItemsViewSource

ItemsSource="{Binding Source={StaticResource groupedItemsViewSource}}"

This is the most important part. groupedItemsViewSource is a CollectionVewSource
       

<CollectionViewSource
    x:Name="groupedItemsViewSource"
    Source="{Binding Products}"
    IsSourceGrouped="true"
    ItemsPath="Items"
    d:Source="{Binding Products, Source={d:DesignInstance Type=data:MainViewModel, IsDesignTimeCreatable=True}}"/>

Pay attention at the d:Source. This is the code which binds the design view with the ViewModel. The 'd' namespace is ignored by the run time. It is used only for design time.
The source is bindend to the Products collection of the MainViewModel. I said before that MainViewModel needs a parameter less constructor. This is the place where the constructor is used. If you don't define it then the source will not bind for design time.

Now if you open the MainPage in Blend it will nicely display the design with all the images in place.

blend-mvvm

Source code is available on GitHub Grouped Items with MvvmLight.

Comments

comments powered by Disqus