A Behavior to handle VisualState in Universal apps with MVVM

29/07/2014 2 comments

Some times ago we talked about a way to handle VisualState in Universal apps using Behavoir SDK and MVVM. In that occasion, we shown how to use DataTriggerBehavior and GotoStateAction to map VisualState to a value of an Enum in the ViewModel.

To make things simpler, we can create a custom Behavior that specifically targets this scenario:

public class EnumStateBehavior : DependencyObject, IBehavior
{
    public DependencyObject AssociatedObject { get; private set; }

    public object Value
    {
        get { return (object)GetValue(ValueProperty); }
        set { SetValue(ValueProperty, value); }
    }

    public static readonly DependencyProperty ValueProperty =
        DependencyProperty.Register("Value", typeof(object), typeof(EnumStateBehavior), 
        new PropertyMetadata(null, ValuePropertyChanged));

    private static void ValuePropertyChanged(object sender, 
        DependencyPropertyChangedEventArgs e)
    {
        var behavior = sender as EnumStateBehavior;
        if (behavior.AssociatedObject == null || e.NewValue == null) return;

        VisualStateManager.GoToState(behavior.AssociatedObject as Control, 
            e.NewValue.ToString(), true);
    }

    public void Attach(DependencyObject associatedObject)
    {
        var control = associatedObject as Control;
        if (control == null)
            throw new ArgumentException(
                "EnumStateBehavior can be attached only to Control");

        AssociatedObject = associatedObject;
    }

    public void Detach()
    {
        AssociatedObject = null;
    }
}

The Behavior defines a Dependency Property called Value (lines 11-13) that must be bound to an Enum. When its value changes, in the ValuePropertyChanged method (lines 15-23) we make a transition using the VisualStateManager to a state with a name that is equals to the enum value itself.

Then, we define a ViewModel as follows:

public class MainViewModel : ViewModelBase
{
    public enum ViewModelState
    {
        Default,
        Details
    }

    private ViewModelState currentState;
    public ViewModelState CurrentState
    {
        get { return currentState; }
        set
        {
            this.Set(ref currentState, value);
        }
    }

    public RelayCommand GotoDetailsStateCommand { get; set; }
    public RelayCommand GotoDefaultStateCommand { get; set; }

    public MainViewModel()
    {
        GotoDetailsStateCommand = new RelayCommand(() =>
        {
            CurrentState = ViewModelState.Details;
        });

        GotoDefaultStateCommand = new RelayCommand(() =>
        {
            CurrentState = ViewModelState.Default;
        });
    }
}

The CurrentState property at lines 10-17 represents the state of the ViewModel, that we can change using the two RelayCommands defined in the constructor.

Finally, in the MainPage.xaml we must bind this property to the behavior using the Behavior SDK:

<Page
    x:Class="MvvmDemo.MainPage"
    DataContext="{Binding Source={StaticResource Locator}, Path=MainViewModel}"
    ...
    xmlns:i="using:Microsoft.Xaml.Interactivity"
    xmlns:behaviors="using:MvvmDemo.Behaviors"
    ...
    >

    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <Grid x:Name="DefaultPanel" HorizontalAlignment="Center" 
              VerticalAlignment="Center">
            <StackPanel>
                <TextBlock Text="Default State" 
                           Style="{StaticResource SubheaderTextBlockStyle}" />
                <Button Margin="0,20,0,0" Content="Go to Details state" 
                        Command="{Binding GotoDetailsStateCommand}" />
            </StackPanel>
        </Grid>

        <Grid x:Name="DetailsPanel" HorizontalAlignment="Center" 
              VerticalAlignment="Center" Visibility="Collapsed">
            <StackPanel>
                <TextBlock Text="Details State" 
                           Style="{StaticResource SubheaderTextBlockStyle}"
                           Foreground="Yellow" />
                <TextBlock Text="Details message here..." 
                           Style="{StaticResource TitleTextBlockStyle}" />
                <Button Margin="0,20,0,0" Content="Go to Default state" 
                        Command="{Binding GotoDefaultStateCommand}" />
            </StackPanel>
        </Grid>

        <VisualStateManager.VisualStateGroups>
            <VisualStateGroup x:Name="ApplicationViewStates">
                <VisualState x:Name="Default"/>

                <VisualState x:Name="Details">
                    <Storyboard>
                        <ObjectAnimationUsingKeyFrames Storyboard.TargetName="DefaultPanel" 
                                                    Storyboard.TargetProperty="Visibility">
                            <DiscreteObjectKeyFrame KeyTime="0" Value="Collapsed"/>
                        </ObjectAnimationUsingKeyFrames>
                        <ObjectAnimationUsingKeyFrames Storyboard.TargetName="DetailsPanel" 
                                                    Storyboard.TargetProperty="Visibility">
                            <DiscreteObjectKeyFrame KeyTime="0" Value="Visible"/>
                        </ObjectAnimationUsingKeyFrames>
                    </Storyboard>
                </VisualState>
            </VisualStateGroup>
        </VisualStateManager.VisualStateGroups>
    </Grid>
    
    <i:Interaction.Behaviors>
        <behaviors:EnumStateBehavior Value="{Binding CurrentState}" />
    </i:Interaction.Behaviors>
</Page>

At lines 34-51 we have created two Visual States with names that correspond to the Enum values specified in the ViewModel. Then, at lines 54-56, we have declared the EnumStateBehavior and bound its Value property to the CurrentState property of the ViewModel. In this way, everytime the latter changes, an automatic transition to the new VisualState will occur.

You can download the working example using the link below.

A Behavior to handle VisualState in Universal apps with MVVM

Categories: C#, MVVM, Windows Phone, WinRT

Handling VisualState in Universal apps with Behavior SDK and MVVM

15/07/2014 6 comments

With VisualState, we can easily create different UIs that can be shown alternately. In Windows 8, for example, it was used by the Basic Page template to define layouts that adapt to orientation and app width. But, in general, we can create different UIs and show them based on the current state of the app. Let’s see how to do that in a Universal Windows app with MVVM Light.

Let’s define the following ViewModel:

public class MainViewModel : ViewModelBase
{
    private enum ViewModelState
    {
        Default,
        Details
    }

    private string currentState;
    public string CurrentState
    {
        get { return currentState; }
        set
        {
            this.Set(ref currentState, value);
        }
    }

    public RelayCommand GotoDetailsStateCommand { get; set; }
    public RelayCommand GotoDefaultStateCommand { get; set; }

    public MainViewModel()
    {
        GotoDetailsStateCommand = new RelayCommand(() =>
        {
            CurrentState = ViewModelState.Details.ToString();
        });

        GotoDefaultStateCommand = new RelayCommand(() =>
        {
            CurrentState = ViewModelState.Default.ToString();
        });
    }
}

The CurrentState property at lines 10-17 represents the state of the ViewModel, that we can change using the two RelayCommands defined in the constructor.

Now we define two VisualStates in the MainPage.xaml page: we want that, when the CurrentState property changes, the VisualState is updated accordingly. To do that with an MVVM approach, we can make use of the Behavior SDK:

<Page
    x:Class="MvvmDemo.MainPage"
    DataContext="{Binding Source={StaticResource Locator}, Path=MainViewModel}"
    ...
    xmlns:i="using:Microsoft.Xaml.Interactivity"
    xmlns:core="using:Microsoft.Xaml.Interactions.Core"
    ...
    >

    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <Grid x:Name="DefaultPanel" HorizontalAlignment="Center" 
              VerticalAlignment="Center">
            <StackPanel>
                <TextBlock Text="Default State" 
                           Style="{StaticResource SubheaderTextBlockStyle}" />
                <Button Margin="0,20,0,0" Content="Go to Details state" 
                        Command="{Binding GotoDetailsStateCommand}" />
            </StackPanel>
        </Grid>

        <Grid x:Name="DetailsPanel" HorizontalAlignment="Center" 
              VerticalAlignment="Center" Visibility="Collapsed">
            <StackPanel>
                <TextBlock Text="Details State" 
                           Style="{StaticResource SubheaderTextBlockStyle}"
                           Foreground="Yellow" />
                <TextBlock Text="Details message here..." 
                           Style="{StaticResource TitleTextBlockStyle}" />
                <Button Margin="0,20,0,0" Content="Go to Default state" 
                        Command="{Binding GotoDefaultStateCommand}" />
            </StackPanel>
        </Grid>

        <VisualStateManager.VisualStateGroups>
            <VisualStateGroup x:Name="ApplicationViewStates">
                <VisualState x:Name="Default"/>

                <VisualState x:Name="Details">
                    <Storyboard>
                        <ObjectAnimationUsingKeyFrames Storyboard.TargetName="DefaultPanel" 
                                                    Storyboard.TargetProperty="Visibility">
                            <DiscreteObjectKeyFrame KeyTime="0" Value="Collapsed"/>
                        </ObjectAnimationUsingKeyFrames>
                        <ObjectAnimationUsingKeyFrames Storyboard.TargetName="DetailsPanel" 
                                                    Storyboard.TargetProperty="Visibility">
                            <DiscreteObjectKeyFrame KeyTime="0" Value="Visible"/>
                        </ObjectAnimationUsingKeyFrames>
                    </Storyboard>
                </VisualState>
            </VisualStateGroup>
        </VisualStateManager.VisualStateGroups>

        <i:Interaction.Behaviors>
            <core:DataTriggerBehavior Binding="{Binding CurrentState}" 
                                      ComparisonCondition="Equal" Value="Default">
                <core:GoToStateAction StateName="Default" />
            </core:DataTriggerBehavior>
            <core:DataTriggerBehavior Binding="{Binding CurrentState}" 
                                      ComparisonCondition="Equal" Value="Details">
                <core:GoToStateAction StateName="Details" />
            </core:DataTriggerBehavior>
        </i:Interaction.Behaviors>
    </Grid>
</Page>

We have defined two grids: the first at lines 11-19 (DefaultPanel) and the other at lines 21-32 (DetailsPanel). The latter is initially collapsed. Thanks to the VisualStateManager, it will be shown when the VisualState of the page changes to Details, using the animations at lines 38-49.

The transition betweeen VisualStates is done using behaviors. In particular, we use a DataTriggerBehavior that checks the value of the CurrentState property: accordingly to its value (lines 54-61), we invoke the GotoStateAction action to actually modify the page state.

That’s all. Everytime we change the value of CurrentState property in the ViewModel, the corresponding trigger will be executed, resulting in a change of the Visual State.

You can download the working example using the link below.

Handling VisualState in Universal apps with Behavior SDK and MVVM

Categories: C#, MVVM, Windows Phone, WinRT

Universal apps, User Controls and MVVM

08/07/2014 2 comments

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

How to send string and content messages with MVVM Light Messenger

25/06/2014 2 comments

The Messenger component of MVVM Light easily allows to pass data between classes of our app:

// Sends a message with a Person object.
var person = new Person { FirstName = "Marco", LastName = "Minerva" };
Messenger.Default.Send(person);

// Registers for incoming Person messages.
Messenger.Default.Register<Person>(this, (person) =>
{
    // Works with the Person object.
});

To send an object, we simply need to pass it to the Messenger.Send method. But what if we just want to send string messages, like GotoDetailsPage or CloseApp?

In this case, we don’t want to create a new class only to pass a string. We can instead use the NotificationMessage object that comes with MVVM Light:

// Sends a notification message with a string content.
Messenger.Default.Send(new NotificationMessage("GotoDetailsPage"));

// Registers for incoming Notification messages.
Messenger.Default.Register<NotificationMessage>(this, (message) =>
{
    // Checks the actual content of the message.
    switch (message.Notification)
    {
        case "GotoDetailsPage":
            break;

        case "OtherMessage":
            break;

        default:
            break;
    }
});

At lines 8-18, we check the Notification property to determine the specific message that has been sent. Of course, we can use constants to avoid the repetition of string values.

We have also a generic version of NotificationMessage that we can use when we want to send an object along with a string message, which for example specifies the action that we want to perform:

// Sends a notification message with a Person as content.
var person = new Person { FirstName = "Marco", LastName = "Minerva" };
Messenger.Default.Send(new NotificationMessage<Person>(person, "Select"));

// Registers for incoming Notification messages.
Messenger.Default.Register<NotificationMessage<Person>>(this, (message) =>
{
    // Gets the Person object.
    var person = message.Content;

    // Checks the associated action.
    switch (message.Notification)
    {
        case "Select":
            break;

        case "Delete":
            break;

        default:
            break;
    }
});

The generic version of NotificationMessage exposes a Content property that contains the actual object. So we can retrieve it and use the Notification value to determine which action to execute.

Categories: C#, MVVM, Windows Phone, WinRT

How to automatically call the CanExecute method when properties change with MVVM Light in Windows and Phone apps

04/06/2014 2 comments

When using commands, usually in an MVVM scenario, we can define a method, CanExecute, that determines whether a command can execute in its current state.

In a such situation, if the CanExecute handler returns false, the associated command can’t be invoked: if the command is bound, for example, to a Button, the latter will be automatically disabled.

When working with MVVM, the state of a command tipically depends on one or more properties of the ViewModel. For example, suppose we are using MVVM Light and we have defined the following class:

public class MainViewModel : ViewModelBase
{
    private string mail;
    public string Mail
    {
        get { return mail; }
        set
        {
            if (this.Set(ref mail, value))
                ConfirmCommand.RaiseCanExecuteChanged();
        }
    }

    private bool privacyConfirmation;
    public bool PrivacyConfirmation
    {
        get { return privacyConfirmation; }
        set
        {
            if (this.Set(ref privacyConfirmation, value))
                ConfirmCommand.RaiseCanExecuteChanged();
        }
    }

    public RelayCommand ConfirmCommand { get; set; }

    public MainViewModel()
    {
        ConfirmCommand = new RelayCommand(() =>
        {
            // ...
        },
        () =>
        {
            return !string.IsNullOrWhiteSpace(mail) && privacyConfirmation;
        });
    }
}

And the corresponding XAML page:

<StackPanel Orientation="Vertical" HorizontalAlignment="Center" VerticalAlignment="Center">
    <TextBox Text="{Binding Mail, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
             Width="300" PlaceholderText="Mail address" />
    <CheckBox IsChecked="{Binding PrivacyConfirmation, Mode=TwoWay}"
              Content="I accept privacy terms"/>
    <Button Content="Confirm" Command="{Binding ConfirmCommand}" />
</StackPanel>

At lines 33-36 of MainViewModel, we have defined the CanExecute method as lambda: the command can be executed only if Mail is inserted and Privacy Confirmation is checked. To make thing works, we need to invoke the RelayCommand.RaiseCanExecuteChanged method when each interested property changes (lines 9-10 and 20-21), so that the system will call the CanExecute handler and determine the new execution state of the command.

Even in this simple example, we can see that, if a command depends on several properties, it is necessary to call the RaiseCanExecuteChanged method every time one of them chages. This can lead to a lot of repetitive code.

To simplify our apps, we can leverage the Messenger object that comes with MVVM Light. The ViewModelBase.Set method has an overload that allows to broadcast a PropertyChangedMessage notification using the Messenger if the corresponding property actually changes. So we can define a class that extends the standard RelayCommand and contains a list of properties on which it depends:

public class AutoRelayCommand : RelayCommand, IDisposable
{
    private ISet<string> properties;

    public AutoRelayCommand(Action execute) 
        : base (execute)
    {
        this.Initialize();
    }

    public AutoRelayCommand(Action execute, Func<bool> canExecute) 
        : base(execute, canExecute)
    {
        this.Initialize();
    }

    private void Initialize()
    {
        Messenger.Default.Register<PropertyChangedMessageBase>(this, true, (property) =>
        {
            if (properties != null && properties.Contains(property.PropertyName))
                this.RaiseCanExecuteChanged();
        });
    }

    public void DependsOn<T>(Expression<Func<T>> propertyExpression)
    {
        if (properties == null)
            properties = new HashSet<string>();

        properties.Add(this.GetPropertyName(propertyExpression));
    }

    private string GetPropertyName<T>(Expression<Func<T>> propertyExpression)
    {
        if (propertyExpression == null)
            throw new ArgumentNullException("propertyExpression");

        var body = propertyExpression.Body as MemberExpression;
        if (body == null)
            throw new ArgumentException("Invalid argument", "propertyExpression");

        var property = body.Member as PropertyInfo;
        if (property == null)
            throw new ArgumentException("Argument is not a property", 
                "propertyExpression");

        return property.Name;
    }

    public void Dispose()
    {
        Messenger.Default.Unregister(this);
    }
}

The key of this class is the DependsOn method, that allows to specify on which properties the command depends. It takes an expression representing a property and adds it to an internal collection. In the Initialize method (lines 17-24), we use the Messenger to register for the PropertyChangedMessageBase notification. When such a message is received, we determine whether the changed property is contained in the list of the monitored ones. If so, we call the RaiseCanExecuteChanged method, which in turns forces the system to invoke the CanExecute handler.

Now we can update the MainViewModel to use this new command type:

public class MainViewModel : ViewModelBase
{
    private string mail;
    public string Mail
    {
        get { return mail; }
        set
        {
            this.Set(ref mail, value, broadcast: true);
        }
    }

    private bool privacyConfirmation;
    public bool PrivacyConfirmation
    {
        get { return privacyConfirmation; }
        set
        {
            this.Set(ref privacyConfirmation, value, broadcast: true);
        }
    }

    public AutoRelayCommand ConfirmCommand { get; set; }

    public MainViewModel()
    {
        ConfirmCommand = new AutoRelayCommand(() =>
        {
            // ...
        },
        () =>
        {
            return !string.IsNullOrWhiteSpace(mail) && privacyConfirmation;
        });

        ConfirmCommand.DependsOn(() => Mail);
        ConfirmCommand.DependsOn(() => PrivacyConfirmation);
    }
}

With the code at lines 36-37, we tell that ConfirmCommand (that now is an AutoRelayCommand) depends on Mail and PrivacyConfirmation properties.

At lines 9 and 19 we have specified true for the brodcast argument of the Set method. In this way, a PropertyChangedMessage is automatically sent whenever these properties change. As said before, the AutoRelayCommand receives the notification and, because of its dependencies, it automatically calls the RaiseCanExecuteChanged method, causing the CanExecute handler to be invoked.

Note that we can follow the same approach also with generic RelayCommand<T> command (and so define an AutoRelayCommand<T> class).

Categories: C#, MVVM, Windows Phone, WinRT

The new flights of the Drone

20/05/2014 Leave a comment

After its first public flight during Community Days in Milan, the AR.Drone 2.0 has continued to be a player in many Italian events. With my friend Marco Dal Pino, we shown new ways to interact with it and how to manage other interesting features.

In April, during Codemotion Rome, we talked about the on board camera and how to stream video to a Windows Phone app. We also shown the possibility to control the drone from a Windows Store app using the Xbox Controller, thanks to the SharpDX library.

Our session has been recorded and it is available on YouTube:

Then, the drone has made many flights during the Fiera del Radioamatore in Perdenone, which for the first time hosted a booth entirely dedicated to the Microsoft ecosystem. It was a great experience, and I hope that in the future we will have other opportunities like that!

The Drone in Pordenone

The Drone in Pordenone

Finally, on May 10 we brought the Drone at .NET Campus in Rome. In that occasion, we introduced a free Class Library that we published on NuGet, AR.Drone 2.0 Interaction Library. It allows to interact with the AR.Drone 2.0 from any application: it is available for Windows, Windows Store and Phone apps and supports all the main commands (takeoff, landing, up, down, left, right and rotate). Moreover, in future releases we will add other important features.

Among the other things, we used this library in conjunction with Intel® Perceptual Computing SDK to show how to control the drone with hand movements. It was a completely new kind of interaction that we never tried before!

The most exciting moment has been when, at the end of our session, attendees asked for a photo with us and, of course, the drone! An unexpected request that has made us really happy!

Photo with attendees and the drone

Photo with attendees and the drone

I want to thank again Microsoft Italia, that has given us the opportunity to experiment with the Drone, finding new and interesting ways to leverage its capabilities.

Categories: Community, Windows Phone, WinRT

MVVM Light and Design Time Data in Windows and Phone apps

08/05/2014 1 comment

Our apps use various kind of services to retrieve data. This information typically aren’t available at design time, because for example are downloaded using online resources.

Using MVVM Light together with its IoC container, it is straightforward to create View Models that uses a certain service at design time, and another one at runtime, without the need to change the code.

Suppose for example that we have a service defined by the following interface:

public interface IDataService
{
    IEnumerable<Person> GetPeople();
}    

public class Person
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

At runtime, people are retrieved through an online service (that may require authentication) and shown in a control like a GridView. But, in order to create the UI of the app, we need to get people also at design time, so we can style the GridView as we want.

To do this, we can define two implementations of the interface, one that actually uses the service, and another that returns dummy data to be used at design time:

public class RuntimeDataService : IDataService
{
    public IEnumerable<Person> GetPeople()
    {
        var people = new List<Person>();

        // In a real scenario, these people are retrived for example via a Web API.
        people.Add(new Person { FirstName = "Donald", LastName = "Duck" });
        people.Add(new Person { FirstName = "Mickey", LastName = "Mouse" });
        people.Add(new Person { FirstName = "Daisy", LastName = "Duck" });

        return people;
    }
}

public class DesignTimeDataService : IDataService
{
    public IEnumerable<Person> GetPeople()
    {
        var people = from n in Enumerable.Range(1, 100)
                     select new Person
                     {
                         FirstName = "Design Time First Name " + n,
                         LastName = "Design Time Last Name " + n
                     };

        return people;
    }
}

Now we need to register these implementations in the ViewModelLocator class (like the one we shown in the previous post about MVVM Light in Universal apps):

public class ViewModelLocator
{
    public ViewModelLocator()
    {
        ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);

        if (ViewModelBase.IsInDesignModeStatic)
        {
            // We are at design time.
            SimpleIoc.Default.Register<IDataService, DesignTimeDataService>();
        }
        else
        {
            // We are at runtime.
            SimpleIoc.Default.Register<IDataService, RuntimeDataService>();
        }

        SimpleIoc.Default.Register<MainViewModel>();
    }

    // ...
}

At line 7 we use the ViewModelBase.IsInDesignModeStatic property to check if we are at design time (in fact, since the ViewModelLocator is declared as a resource in the App.xaml file, it is automatically instantiated, even if the app isn’t explicitly executed). If so, we register in the MVVM Light SimpleIoC container the type DesignTimeDataService for the interface IDataService. Otherwise, if we are at execution time we register the type RuntimeDataService.

Now we can pass an object implementing the IDataService interface to our View Model:

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

    public MainViewModel(IDataService dataService)
    {
        var peopleList = dataService.GetPeople();
        People = new ObservableCollection<Person>(peopleList);
    }
}

In this way, when we are at design time, the type passed to MainViewModel is DesignTimeDataService, and so if we bind the People property to a GridView of a Windows Store app, we’ll obtain something like this in the Visual Studio Designer (it could be necessary to build the project to see the dummy data):

Design Time Data with MVVM Light

Design Time Data with MVVM Light

On the other hand, as we can imagine, at execution time that type received by MainViewModel is RuntimeDataService, so we’ll obtain:

Runtime Data with MVVM Light

Runtime Data with MVVM Light

Moreover, we can check if we are at design time or execution time also inside a ViewModel, using the IsInDesignMode property:

public class MainViewModel : ViewModelBase
{
    public MainViewModel()
    {
        if (IsInDesignMode)
        {
            // We are at design time.
            // ...
        }
        else
        {
            // We are at runtime.
            // ...
        }
    }
}

Note that this use of Design Time data is supported by Blend as well, so we can leverage the same approach to create our user interfaces also with this application.

Categories: C#, MVVM, Windows Phone, WinRT
Follow

Get every new post delivered to your Inbox.