Using MVVM Light ViewModelBase class with Template 10

25/01/2016 1 comment

Template10 comes with a handful ViewModelBase class that provides an easy way to handle events such as OnNavigatedTo, OnNavigatingFrom, access the Navigation Service from View Models and so on. In the previous posts we have seen how to integrate this class with MVVM Light, but what if we already have View Models that inherit from MVVM Light ViewModelBase, or as usually happens we have our ViewModelBase class, that in turns inherits from MVVM Light one?

If our View Models directly inherit from MVVM Light ViewModelBase class, we simply need to implement the Template 10 INavigable interface:

public class MainViewModel : GalaSoft.MvvmLight.ViewModelBase,
    Template10.Services.NavigationService.INavigable
{
    public Task OnNavigatedToAsync(object parameter, NavigationMode mode, 
        IDictionary<string, object> state)
    {
        // ...
        return Task.CompletedTask;
    }

    public Task OnNavigatedFromAsync(IDictionary<string, object> state, 
        bool suspending)
    {
        // ...
        return Task.CompletedTask;
    }

    public Task OnNavigatingFromAsync(NavigatingEventArgs args)
    {
        // ...
        return Task.CompletedTask;
    }

    [JsonIgnore]
    public IDispatcherWrapper Dispatcher { get; set; }

    [JsonIgnore]
    public INavigationService NavigationService { get; set; }

    [JsonIgnore]
    public IStateItems SessionState { get; set; }
}

In this case the recommended approach is of course to create a base class that inherits from MVVM Light ViewModelBase class and implements the Template 10 INavigable interface:

public abstract class MyViewModelBase : GalaSoft.MvvmLight.ViewModelBase,
    Template10.Services.NavigationService.INavigable
{
    public virtual Task OnNavigatedToAsync(object parameter, 
        NavigationMode mode, IDictionary<string, object> state) 
        => Task.CompletedTask;

    public virtual Task OnNavigatedFromAsync(IDictionary<string, object> state,
        bool suspending) 
        => Task.CompletedTask;

    public virtual Task OnNavigatingFromAsync(NavigatingEventArgs args)
        => Task.CompletedTask;

    [JsonIgnore]
    public IDispatcherWrapper Dispatcher { get; set; }

    [JsonIgnore]
    public INavigationService NavigationService { get; set; }

    [JsonIgnore]
    public IStateItems SessionState { get; set; }
}

As said before, if we already have our custom ViewModelBase class, we just need to make it implement the INavigable interface in the same way. In any cases, after defining this class, we can use it as usual:

public class MainViewModel : MyViewModelBase
{
    private string name;
    public string Name
    {
        get { return name; }
        set { base.Set(ref name, value, broadcast: true); }
    }

    public override Task OnNavigatedToAsync(object parameter,
        NavigationMode mode, IDictionary<string, object> state)
    {
        var argument = parameter?.ToString();

        if (state.Any())
        {
            //...

            state.Clear();

        }

        // Calls a method from MVVM Light ViewModelBase class.
        base.Broadcast(null, "Marco", nameof(Name));

        return base.OnNavigatedToAsync(parameter, mode, state);
    }
}

We can now access all the features provided by either MVVM Light and Template 10 without further code refactoring.

Using MVVM Light Messenger with Template 10

30/11/2015 1 comment

In previous posts we shown how to integrate MVVM Light with Template 10. We still need to talk about an important component of the toolkit, the Messenger. It allows for communication within the application, i.e. between View Models, Views and View Models, and so on.

We can access the Messenger from anywhere in our code, using its static Messenger.Default property. So, for example, we can easily integrate it in a View Model even if it inherits from the Template 10 ViewModelBase class (instead of the MVVM Light base class).

The first thing we can do with the Messenger is sending object, i.e. to execute code in the View Model in response to View event handlers:

private void GridView_ItemClick(object sender, ItemClickEventArgs e)
{
    // Sends a message with a Person object.
    var person = e.ClickedItem as Person;
    Messenger.Default.Send(person);
}

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

MVVM Light provides also a built-in class, NotificationMessage, that we can use if we just want to send string messages:

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

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

        default:
            break;
    }
});

At lines 8-15, 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 can combine both of these scenarios and use the generic version of NotificationMessage to send an object along with a string message, which for example specifies the action that we want to perform:

private void GridView_ItemClick(object sender, ItemClickEventArgs e)
{
    // Sends a message with a Person object.
    var person = e.ClickedItem as Person;

    // Sends a notification message with a Person as content.
    Messenger.Default.Send(new NotificationMessage<Person>(person, "Select"));
    //Messenger.Default.Send(new NotificationMessage<Person>(person, "Update"));
}

// In the View Model...
// 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 "Update":
            break;

        default:
            break;
    }
});

The generic version of NotificationMessage exposes a Content property (line 16) that contains the actual object. So we can retrieve it and use the Notification value to determine which action to execute (lines 19-29).

In some cases, we would need to execute an action back on the sender when the message is received. For these scenarios, MVVM Light provides the NotificationMessageAction class, which allows to specify a callback method that can be executed by the recipient to notify the sender that the message has been processed. With this object, however, we can only send a notification string message. So what about if we want to send also a content class, like in the generic NotificationMessage?

First of all, we need to define a class that inherits from the standard NotificationMessageAction class:

public class NotificationMessageAction<T, TCallbackParameter> 
    : NotificationMessageAction<TCallbackParameter>
{
    public T Content { get; }

    public NotificationMessageAction(T content, string notification, 
        Action<TCallbackParameter> callback)
      : base(notification, callback)
    {
        Content = content;
    }
}

Basically, we have added the generic Content property (line 4). Then, we can write something like this:

private void GridView_ItemClick(object sender, ItemClickEventArgs e)
{
    // Sends a message with a Person object.
    var person = e.ClickedItem as Person;

    // Sends a notification message with a Person as content, 
    // a string message and a callback to be executed at the end.
    Messenger.Default.Send(new NotificationMessageAction<Person, int>(person, 
        "Update", (response) => 
    {
        // "response" contains the response (int in this example) from the
        // receiver.
    }));
}

// In the View Model...
// Registers for incoming NotificationMessageAction messages.
Messenger.Default.Register<NotificationMessageAction<Person, int>>(this, 
    (message) =>
{
    // Gets the Person object.
    var person = message.Content;

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

        default:
            break;
    }

    // Executes the callback.
    message.Execute(42);
});

At lines 8-13 we send our NotificationMessageAction message, specifying that Content is a Person and the callback parameter is int. Then, in the View Model we process the message as we did in the previous example (lines 21-32) and finally we execute the callback (line 35): this instruction will cause the action defined at lines 10-13 to be executed.

If we use an IoC Container for View Models (like MVVM Light SimpleIoC), we must remember that Messenger registrations remain active even if we change View (because View Models actually stay in memory), so they always receive notifications. Instead, we usually want that a View Model receives notification only if its corresponding View is active.

To overcome this problem, we simply can register messages in the Template 10 OnNavigatedTo method and unregister them in OnNavigatedFromAsync:

public override void OnNavigatedTo(object parameter, NavigationMode mode,
    IDictionary<string, object> state)
{
    // Registers for incoming Person messages.
    Messenger.Default.Register<Person>(this, (p) =>
    {
        
    });

    base.OnNavigatedTo(parameter, mode, state);
}

public override Task OnNavigatedFromAsync(IDictionary<string, object> state, 
    bool suspending)
{
    // Unregisters all messages registered by this receiver.
    Messenger.Default.Unregister(this);

    return base.OnNavigatedFromAsync(state, suspending);
}

To unregister a messenger recipient completely, we simply need to call the Unregister method, passing the receiver reference (line 17).

Windows 10 IoT Core on ioProgrammo

12/10/2015 Comments off

I have written a new article for the n°200 of ioProgrammo (November/December 2015). This time I talk about Windows 10 IoT Core: from installation to first experiments with Raspberry Pi 2, we’ll explore the “T” part of the Internet of Things.

ioProgrammo November/December 2015

ioProgrammo November/December 2015

Categories: General

NavigationService with MVVM Light and Template 10

07/10/2015 1 comment

Navigation is one of the most important part of every Universal Windows app. If you are accustomed to use MVVM Light, probably you already leverage the NavigationService this toolkit provides.

Template 10 too comes with its own NavigationService. It is accessible from the Application BootStrapper class and directly from classes inheriting from ViewModelBase.

First versions of Template 10 allowed to navigate by page type, which is the standard on the XAML Frame. If, however, we are following the MVVM pattern, and so we control navigation from view models, this approach isn’t correct, because view models shouldn’t know anything about pages. In fact, NavigationService from MVVM Light requires to associate each page type to a key and then use it to handle navigation from views models (as described in the article Navigation Service in MVVM Light 5).

Last version of Template 10 (1.0.4 on NuGet) improves its NavigationService by providing a similar approach based on keys, in order to isolate view types from view models. Let’s see how to use it.

The first step is creating a custom Enum that represents the pages of our app:

public enum Pages
{
    MainPage,
    DetailsPage,
    OtherPage,
    //...
}

Then, we need to populate the PageKeys dictionary exposed by BootStrapper. We can do this in the OnInitializeAsync method:

public override Task OnInitializeAsync(IActivatedEventArgs args)
{
    var keys = PageKeys<Pages>();
    keys.Add(Pages.MainPage, typeof(MainPage));
    keys.Add(Pages.DetailsPage, typeof(DetailsPage));

    return base.OnInitializeAsync(args);
}

We’re associating each page type with the corresponding enum value (lines 4-5). In this way, we can use an overload of the NavigationService.Navigate method that takes as first argument the enum value corresponding to the page type we want to navigate to (instead of use the page type directly). For example:

NavigationService.Navigate(Pages.MainPage);

// Navigation with parameters.
NavigationService.Navigate(Pages.DetailsPage, "parameters");

You can find a sample of this approach in the official Template 10 GitHub repository (thanks to Jerry Nixon for accepting my pull request!). As said, this is strongly recommended when we use the MVVM pattern.

Using IoC and Design time support with MVVM Light and Template 10

23/09/2015 3 comments

In the last post we talked about Integrating Template10 with MVVM Light. Now let’s see how to use some basic services provided by MVVM Light, starting with SimpleIoC and Design time support.

In the previous post we already used it to register a simple ViewModel, but it is more powerful, and for example we can leverage it to inject dependencies. For example, let’s define the following service:

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

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

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;
    }
}

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;
    }
}

The IDataService interface defines a method the retrieves a list of people. Then we have a design and a runtime implementation. We need to register them in the ViewModelLocator class:

public class ViewModelLocator
{
    static ViewModelLocator()
    {
        ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);
 
        if (GalaSoft.MvvmLight.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 MVVM Light 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 : Template10.Mvvm.ViewModelBase
{
    private IEnumerable<Person> people;
    public IEnumerable<Person> People
    {
        get { return people; }
        set { this.Set(ref people, value); }
    }

    private readonly IDataService dataService;

    public MainViewModel(IDataService dataService)
    {
        this.dataService = dataService;

        if (GalaSoft.MvvmLight.ViewModelBase.IsInDesignModeStatic)
        {
            // Loads people to enable desgin time support.
            People = dataService.GetPeople();
        }
    }

    public override void OnNavigatedTo(object parameter, NavigationMode mode, 
        IDictionary<string, object> state)
    {
        // Loads real data.
        People = dataService.GetPeople();

        base.OnNavigatedTo(parameter, mode, state);
    }
}

In this way, when we are at design time, the type passed to MainViewModel is DesignTimeDataService, while at execution time we’ll have a RuntimeDataService. In fact, in the MainViewModel constructor (lines 12-20) we check whether we are actually at design time, and so we call the GetPeople method, in order to show dummy data (from DesignTimeDataService) to enable design time support. Note that we again use a method available in the ViewModelBase class that comes from MVVM Light, and not the Template10 ViewModelBase implementation from which the View model inherits:

Design Time data

Design Time data

Finally, in the Template 10 OnNavigatedTo method (lines 23-30), we call again GetPeople: as this method is executed when we are at runtime, now we’re retrieving information from RuntimeDataService:

Runtime data

Runtime data

Working with interfaces and implementations is strongly recommended. Besides allowing design time support, as we have just seen, it make easier to test our code. MVVM Light provides all the tools that we need to do that (like a simple IoC container), and integrating it in a project built with Template 10 is straightforward.

You can download the complete example using the link below:
Using IoC with MVVM Light and Template10

Integrating Template10 with MVVM Light

15/09/2015 4 comments

Template10 is an advanced project template for the Unversal Windows Platform. It’s an open source project available on GitHub at https://github.com/Windows-XAML/Template10. If you don’t know about it, I suggest you to read the great article Template10: a new template to create Universal Windows apps – The basics by Matteo Pagani (Support Engineer at Microsoft).

The template has been created with MVVM in mind, and in fact contains some useful classes that simplify the adoption of this pattern (like BindableBase and ViewModelBase). But it isn’t an MVVM Framework (or toolkit). However, it’s easy to integrate Template10 with, for example, MVVM Light. Let’s see how to do that.

First of all, let’s add the template to our app, as described in the post linked above (you can also find it on NuGet). Then, we need to add MVVM Light using NuGet: search for the MvvmLightLibs package and install it. As NuGet 3.0 doesn’t allow anymore to run installation script, even if we choose the MvvmLight package, it will not install additional files like ViewModelLocator, nor it will modify the App.xaml file with its reference. So, we need to perform these steps manually.

Let’s create a folder called ViewModels with a MainViewModel.cs file:

public class MainViewModel : Template10.Mvvm.ViewModelBase
{
    public string HelloMessage { get; }

    public MainViewModel()
    {
        HelloMessage = "Hello from Mvvm!";
    }

    public override void OnNavigatedTo(object parameter, NavigationMode mode, 
        IDictionary<string, object> state)
    {
        base.OnNavigatedTo(parameter, mode, state);
    }
}

Note that MainViewModel inherits from a class contained in the Template10 (that, among the others, define the OnNavigatedTo method: as we’ll see, it we’ll be invoked when the user navigates to the associated page.

Now we need to implement a ViewModelLocator:

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

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

    public MainViewModel MainViewModel 
        => ServiceLocator.Current.GetInstance<MainViewModel>();
}

Finally, let’s insert the ViewModelLocator in the Application Resources (App.xaml):

<common:BootStrapper
    ...>

    <Application.Resources>
        <ResourceDictionary>
            <vm:ViewModelLocator x:Key="Locator" 
                            xmlns:vm="using:Template10MvvmLight.ViewModels" />
        </ResourceDictionary>
    </Application.Resources>
    
</common:BootStrapper>

And set the DataContext of MainPage.xaml:

<Page
    x:Class="Template10MvvmLight.MainPage"
    DataContext="{Binding Source={StaticResource Locator}, Path=MainViewModel}"
    ...>

    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <TextBlock Text="{Binding HelloMessage}" HorizontalAlignment="Center"
                   VerticalAlignment="Center" />
    </Grid>
</Page>

We can now test the app. Set a breakpoint in the OnNavigatedTo method of the MainViewModel class and run the project: as we expect, it will be called on page activation and then the TextBlock will show the HelloMessage property of the view model.

You can download the complete example using the link below:
Integrating Template10 with MVVM Light

In the next post, we’ll see how to use the other services provided by MVVM Light, so stay tuned!

FullScreenModeTrigger for Universal Windows Platform

14/07/2015 2 comments

Last week we talked about full-screen mode in Windows 10 Universal apps. In this scenario, we could have the need to adjust the UI when we enter full-screen mode. The best way to do so is to create an Adaptive Trigger:

public class FullScreenModeTrigger : StateTriggerBase
{
    public bool IsFullScreen
    {
        get { return (bool)GetValue(IsFullScreenProperty); }
        set { SetValue(IsFullScreenProperty, value); }
    }

    public static readonly DependencyProperty IsFullScreenProperty =
        DependencyProperty.Register("IsFullScreen", typeof(bool), 
        typeof(FullScreenModeTrigger),
        new PropertyMetadata(false, OnIsFullScreenPropertyChanged));

    private static void OnIsFullScreenPropertyChanged(DependencyObject d, 
        DependencyPropertyChangedEventArgs e)
    {
        var obj = (FullScreenModeTrigger)d;
        if (!Windows.ApplicationModel.DesignMode.DesignModeEnabled)
        {
            var isFullScreen = ApplicationView.GetForCurrentView().IsFullScreenMode;
            obj.UpdateTrigger(isFullScreen);
        }
    }

    public FullScreenModeTrigger()
    {
        if (!Windows.ApplicationModel.DesignMode.DesignModeEnabled)
            ApplicationView.GetForCurrentView().VisibleBoundsChanged += 
                FullScreenModeTrigger_VisibleBoundsChanged;
    }

    private void FullScreenModeTrigger_VisibleBoundsChanged(ApplicationView sender, 
        object args)
    {
        UpdateTrigger(sender.IsFullScreenMode);
    }

    private void UpdateTrigger(bool isFullScreen)
    {
        SetActive(isFullScreen == IsFullScreen);
    }
}

It defines a dependency property (line 9-12) that specifies if we want to activate the trigger when in full-screen or windowed mode. Then, in the constructor we register on the ApplicationView.VisibleBoundsChanged event (line 28-29). In its event handler (lines 32-36), we check ApplicationView.IsFullScreenMode and activate the trigger based on the value of the IsFullScreen property.

Now we can use this trigger in XAML:

<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
  <StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
      <TextBlock x:Name="fullScreenModeStatus"  
                 HorizontalAlignment="Center" 
                 VerticalAlignment="Center" />
      <Button x:Name="fullScreenMode" Content="Toggle Full Screen Mode" 
              Click="fullScreenMode_Click" />
  </StackPanel>

  <VisualStateManager.VisualStateGroups>
      <VisualStateGroup >
          <VisualState x:Name="fullScreen">
              <VisualState.StateTriggers>
                  <triggers:FullScreenModeTrigger IsFullScreen="true" />
              </VisualState.StateTriggers>
              <VisualState.Setters>
                  <Setter Target="fullScreenModeStatus.Text" 
                          Value="App is in full screen mode" />
                  <Setter Target="fullScreenMode.Content" Value="Exit full screen" />
              </VisualState.Setters>
          </VisualState>
          <VisualState x:Name="windowed">
              <VisualState.StateTriggers>
                  <triggers:FullScreenModeTrigger IsFullScreen="false" />
              </VisualState.StateTriggers>
              <VisualState.Setters>
                  <Setter Target="fullScreenModeStatus.Text" 
                          Value="App is in windowed mode" />
                  <Setter Target="fullScreenMode.Content" Value="Enter full screen" />
              </VisualState.Setters>
          </VisualState>
      </VisualStateGroup>
  </VisualStateManager.VisualStateGroups>
</Grid>

We have defined two visual states (lines 12-21 and 22-32), that are activated according to the value of the IsFullScreen property (lines 14 and 24).

Finally, in the code behind of the page let’s insert the code to enter and exit the full-screen mode:

private void fullScreenMode_Click(object sender, RoutedEventArgs e)
{
    var view = ApplicationView.GetForCurrentView();
    var isFullScreenMode = view.IsFullScreenMode;

    if (isFullScreenMode)
        view.ExitFullScreenMode();
    else
        view.TryEnterFullScreenMode();
}

We simply use a button to toggle the full-screen mode, as described in the previous post.

Follow

Get every new post delivered to your Inbox.

Join 53 other followers