Clear history in Xamarin Android with MVVM Light NavigationService

14/03/2016 Leave a comment

If we’re working with Xamarin, MVVM Light provides quite useful helpers (derived from the Windows implementation) that simplify a lot our work. Among the others, we have a INavigationService class that abstracts the concept of starting a new Activity (Android) rather than activating a certain Controller (iOS), providing a unique approach to page navigation.

This approach is general and the interface is the same on all the platforms. While this helps having a common navigation system, it can leads to platform specific problem. Imagine we are on Android and we need to delete history (for example, after a login). On this platform, navigation history can be deleted only in conjunction with the start of an Activity (i.e., we need to tell Android to delete any existing task before starting the Activity). But if we’re using INavigationService, we have a NavigateTo method to which we can pass only the pageKey and an optional object that will be received by the new activity. We haven’t control on how the new activity is started. So, how can we delete history?

We can tweak the original NavigationService implementation for Android to handle this scenario. First of all, we need to define a NavigationParameter class:

public class NavigationParameter
{
    public ActivityFlags? Flags { get; }

    public object Content { get; }

    public NavigationParameter(ActivityFlags? flags = null)
    {
        Flags = flags;
    }

    public NavigationParameter(object content, ActivityFlags? flags = null)
    {
        Content = content;
        Flags = flags;
    }
}

It allows us to pass custom activation flags rather the a single object to the NavigateTo method. To use this class, a little modification to NavigationService.cs file is requested. Let’s get the original implementation from CodePlex. Then, locate the following code in the NavigateTo(string pageKey, object parameter) method:

if (parameter != null)
{
    lock (_parametersByKey)
    {
        // ...
    }
}

We need to replace it with the following code:

if (parameter != null)
{
    lock (_parametersByKey)
    {
        var guid = Guid.NewGuid().ToString();

        var flags = (parameter as NavigationParameter)?.Flags;
        var actualParameter = (parameter as NavigationParameter)?.Content 
            ?? parameter;

        _parametersByKey.Add(guid, actualParameter);
        intent.PutExtra(ParameterKeyName, guid);

        if (flags.HasValue)
            intent.SetFlags(flags.Value);
    }
}

The core of the change is at lines 7-9. We check if parameter is a NavigationParameter: in this case, we extract the activation flags and the actual parameter; otherwise, we assume we don’t have any activation flag and that the actual parameter is the parameter argument itself. So, we can continue to use the NavigateTo method in the usual way (no breaking changes). Then, at lines 14-15, if flags has value, we pass it to the Intent.SetFlags method.

So, when we need to clear history, we just need to create a NavigationParameter with the correct activation flags, like in the following example:

private NavigationParameter CreateParameter<T>(T parameter, bool clearHistory)
{
    var flags = clearHistory ? (ActivityFlags.NewTask | ActivityFlags.ClearTask) 
        : default(ActivityFlags);
    var args = new NavigationParameter(parameter, flags);

    return args;
}
        
private void NavigateToHomePage<T>(T parameter)
{
    var args = this.CreateParameter(parameter, clearHistory: true);
    navigationService.NavigateTo(Constants.HomePage, args);
}

Note that, as we use NavigationParamenter only to pass activation flags and the new activity receives always the actual parameter, the GetAndRemoveParameter(Intent) method will keep working in the usual way. Moreover, as already said, we can continue to use NavigateTo method as before if we don’t need to clear history.

Categories: C#, MVVM, Xamarin

Pay attention to .NET Native when using Reflection (MVVM scenario)

22/02/2016 Comments off

Among the other things, .NET Native tries to reduce the app size by analyzing the code and striping out unused .NET objects. This approach works very well, but we need to pay attention when we you work with Reflection, because in this case we must explicitly tell to .NET Native which elements are available for it.

A particular scenario occurs if we’re following the MVVM pattern and we have a classic app with a GridView or a ListView and we want to invoke a command when the user clicks an item, passing the item itself to the command. With the Universal Windows Platform, this task can be accomplished using an EventTriggerBehavoir form XamlBehavoirs along with an InvokeCommandAction and an InputConverter:

<GridView IsItemClickEnabled="True" ItemsSource="{Binding People}">
    <GridView.ItemTemplate>
        <DataTemplate>
            ...
        </DataTemplate>
    </GridView.ItemTemplate>

    <Interactivity:Interaction.Behaviors>
        <Interactions:EventTriggerBehavior EventName="ItemClick">
            <Interactions:InvokeCommandAction 
                Command="{Binding ItemSelectedCommand}" 
                InputConverter="{StaticResource EventArgsConverter}" 
                InputConverterParameter="ClickedItem" />
        </Interactions:EventTriggerBehavior>
    </Interactivity:Interaction.Behaviors>
</GridView>

At lines 9-14 we use an EventTriggerBehavior to catch the ItemClick event of the GridView and execute in response the ItemSelectedCommand action of the ViewModel. Thanks to InputConverter and InputConverterParamter (lines 12-13), this action automatically receives the clicked item as argument:

public sealed class EventArgsConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, 
        string language)
    {
        if (value != null)
        {
            var propertyPath = parameter as string;
            if (!string.IsNullOrWhiteSpace(propertyPath))
            {
                var propertyPathParts = propertyPath.Split('.');
                object propertyValue = value;
                foreach (var propertyPathPart in propertyPathParts)
                {
                    var propInfo = propertyValue.GetType().GetTypeInfo().
                        GetDeclaredProperty(propertyPathPart);

                    propertyValue = propInfo.GetValue(propertyValue);
                }

                return propertyValue;
            }
        }

        return value;
    }

    public object ConvertBack(object value, Type targetType, object parameter, 
        string language)
    {
        throw new NotImplementedException();
    }
}

This Converter extracts the property name of the event argument that is passed as parameter (line 8, in this case ClickedItem) and then uses Reflection (lines 15-18) to get the actual value that will be received by the command.

This code works without problem in Debug mode, but when we switch to Release, enabling the .NET Native toolchain (that is required for app submission), if we click an item on the grid we’ll get a runtime error like the following one:

Unhandled exception at 0x77026D7E (combase.dll)

This occurs because the .NET Native toolchain has removed the ItemClickEventArgs class from the compiled code, as it hasn’t found any reference to it in the code, because it is accessed only at runtime through Reflection.

So, as said at the beginning we need to tell to .NET Native to keep this type during compilation. Let’s open the file Default.rd.xml inside the project Properties folder: it contains the Runtime Directives for .NET Native. All that we need is to add a declaration for the ItemClickEventArgs type:

<Directives xmlns="http://schemas.microsoft.com/netfx/2013/01/metadata">
    <Application>
        <!--
          An Assembly element with Name="*Application*" applies to all 
          assemblies in the application package. The asterisks are not 
          wildcards.
        -->
        
        <Assembly Name="*Application*" Dynamic="Required All" />

        <!-- Add your application specific runtime directives here. -->
        <Type Name="Windows.UI.Xaml.Controls.ItemClickEventArgs" 
              Dynamic="Required Public" />

    </Application>
</Directives>

At lines 12-13 we have specified that we want to keep the ItemClickEventArgs type in compilation, even if it isn’t statically referenced in the code. Now we can compile the app in Release mode again: this time everything will work as expected.

We can refer to MSDN documentation to get more information about the Runtime Directives Configuration File.

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

Follow

Get every new post delivered to your Inbox.

Join 54 other followers