Home > C#, MVVM, Windows Phone, WinRT > Universal apps, User Controls and MVVM

Universal apps, User Controls and MVVM

08/07/2014

In Universal Windows apps, User Controls are one of the suggested strategies to keep some UI platform specificities while having some of the XAML shared. In this way, we can easily change the aspect of certain areas of our pages.

Thanks to the MVVM pattern, following this approach is straightforward: we can simply bind the User Control to the appropriate properties of the ViewModel to share the same application logic, without the need to replicate the code.

For example, let’s suppose we want to show a people list with different controls: a GridView on Windows 8.1 and a ListView on Windows Phone. Also the DataTemplate will be different, and the User Control of the Windows project will contain an header.

First of all, let’s define the following ViewModel using MVVM Light:

public class MainViewModel : ViewModelBase
{
    public IEnumerable<Person> People { get; set; }

    public RelayCommand LoadCommand { get; set; }

    public MainViewModel()
    {
        LoadCommand = new RelayCommand(() =>
        {
            var list = from n in Enumerable.Range(1, 100)
                       select new Person
                       {
                           FirstName = "First Name " + n,
                           LastName = "Last Name" + n,
                           ImageUri = (n % 2 == 0) ? new Uri("ms-appx:///Assets/Male.png")
                                                 : new Uri("ms-appx:///Assets/Female.png")
                       };

            People = new List<Person>(list);
            RaisePropertyChanged(() => People);
        });
    }
}

The LoadCommand loads a list of people and sets it to the People property. Now add a MainPage.xaml page in the Shared project:

<Page
    x:Class="MvvmDemo.MainPage"
    DataContext="{Binding Source={StaticResource Locator}, Path=MainViewModel}"
    ...
    xmlns:controls="using:MvvmDemo.UserControls"
    >

    <Page.BottomAppBar>
        <CommandBar>
            <CommandBar.PrimaryCommands>
                <AppBarButton Icon="Refresh" Label="Load" 
                              Command="{Binding LoadCommand}" />
            </CommandBar.PrimaryCommands>
        </CommandBar>
    </Page.BottomAppBar>

    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <controls:PeopleList DataContext="{Binding People}" />
    </Grid>
</Page>

The page contains an AppBar with an icon the invokes the LoadCommand command. At line 18, we insert a PeopleList User Control in the page and we set its DataContext to the People property of the ViewModel. This is the control that we must define in the Windows and Windows Phone project:

<!-- Windows User Control -->
<Grid Margin="120,120,56,32">
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto" />
        <RowDefinition Height="*" />
    </Grid.RowDefinitions>
    <TextBlock Text="People list" Style="{StaticResource HeaderTextBlockStyle}"
               Margin="0,0,0,20"/>
    <GridView Grid.Row="1" ItemsSource="{Binding}">
        <GridView.ItemTemplate>
            <DataTemplate>
                <StackPanel Orientation="Horizontal">
                    <Image Height="120" Width="120" Source="{Binding ImageUri}" />
                    <TextBlock>
                        <Run Text="{Binding FirstName}" />
                        <Run Text="{Binding LastName}" />
                    </TextBlock>
                </StackPanel>
            </DataTemplate>
        </GridView.ItemTemplate>
    </GridView>
</Grid>

<!-- Windows Phone User Control -->
<Grid Margin="12">
    <ListView ItemsSource="{Binding}">
        <ListView.ItemTemplate>
            <DataTemplate>
                <StackPanel Orientation="Horizontal" Margin="5,5,5,10">
                    <Image Height="50" Width="50" Source="{Binding ImageUri}" />
                    <StackPanel>
                        <TextBlock Text="{Binding FirstName}"
                                   Style="{StaticResource BodyTextBlockStyle}" />
                        <TextBlock Text="{Binding LastName}" 
                                   Style="{StaticResource BodyTextBlockStyle}"
                                   FontWeight="Bold" />
                    </StackPanel>
                </StackPanel>
            </DataTemplate>
        </ListView.ItemTemplate>
    </ListView>
</Grid>

At lines 9 and 26, we set the ItemsSource property of GridView and ListView to the DataContext of the control itself, that, as we said before, is bound to the People property of the ViewModel.

So, in this simple example the Windows and Phone projects share the same application logic (i.e. the ViewModel) and part of the User Interface (MainPage.xaml), but each one uses a specific control to show people list.

On Windows:

The Windows Store app

The Windows Store app

And on Windows Phone:

The Windows Phone app

The Windows Phone app

The page is the same, but the list is shown with two different controls, each one tailored to the platform it addresses.

You can download the working example using the link below.

Universal apps, User Controls and MVVM

Categories: C#, MVVM, Windows Phone, WinRT
Comments are closed.
%d bloggers like this: