Custom Map Renderer on Android: Part 3

This is the final post in the series about custom map renderers on Android. To recap, we added a map page to our application and then customized the appearance of the map markers and the info window that is shown when the user taps a marker.

Now we are going to make the map a bit more usable by making it possible to update the pins from the view model, and making it easy to consume services in the Android specific project.

In the previous post, we defined a CustomMap control that only had one property:


public class CustomMap : Map
{
    public List<CustomPin> CustomPins { get; set; }
}

The property above is only available from the ContentPage code behind. We are going to change this to be a bindable property that can be bound in the view model itself.


public class CustomMap : Map
{
    public static readonly BindableProperty CustomPinsProperty =
        BindableProperty.Create(
            "CustomPins",
            typeof(List<CustomPin>),
            typeof(CustomMap),
            new List<CustomPin>(),
            BindingMode.TwoWay);

    public List<CustomPin> CustomPins
    {
        get { return (List<CustomPin>) GetValue(CustomPinsProperty); }
        set { SetValue(CustomPinsProperty, value);
    }
}

Now that CustomPins is a bindable property it can participate in the data binding system. We can setup a property in our view model and attach it in our XAML.


    <view:CustomMap x:Name="cusmap"
IsShowingUser="True" MapType="Street"
CustomPins="{Binding CustomPins, Mode=TwoWay}" />

And here is the property in the view model:


/// other properties
private List<CustomPin> _customPins = new List<CustomPin>();
public List<CustomPin> CustomPins
{
    get { return _customPins; }
    set { SetProperty<List<CustomPin>>(ref _customPins, value); }
}

Finally, we need to get our CustomMapRenderer to react to these changes. The way we do that is to override the OnElementPropertyChangedEvent to list for changes in the CustomPins property.


public class CustomMapRenderer : MapRenderer, GoogleMap.IInfowindowAdapter, IOnMapReadyCallback
{
    // .... all the other code

    protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        base.OnElementPropertyChanged(sender, e);

        if (Element == null || Control == null)
            return;

        if (e.PropertyName == CustomMap.CustomPinsProperty.PropertyName)
        {
            UpdatePins();
        }
    }
}

Finally, I want to show how you can use that data binding technique to pass some services through to your Android project. For example, when a user taps a marker on the map, the info window will show. We can listen for when the user taps on that info window and use our Prism navigation service to pull up a new page. Let’s add the new bindable property to the CustomMap class.


public class CustomMap : Map
{
    public static readonly BindableProperty CustomPinsProperty =
        BindableProperty.Create(
            "CustomPins",
            typeof(List<CustomPin>),
            typeof(CustomMap),
            new List<CustomPin>(),
            BindingMode.TwoWay);

    public List<CustomPin> CustomPins
    {
        get { return (List<CustomPin>) GetValue(CustomPinsProperty); }
        set { SetValue(CustomPinsProperty, value); }
    }

    public static readonly BindableProperty NavigationServiceProperty =
        BindableProperty.Create(
            "NavigationService",
            typeof(Prism.Navigation.INavigationService),
            typeof(CustomMap),
            null);

    public Prism.Navigation.INavigationService NavigationService
    {
        get { return (Prism.Navigation.INavigationService) GetValue(NavigationServiceProperty); }
        set { SetValue(NavigationServiceProperty, value); }
    }
}

Let’s make sure the navigation service is exposed in our view model and then bind it in XAML. Here’s the view model:


public class MapViewModel : BaseViewModel
{
    public MapViewModel(INavigationService navigationService)
        : base()
    {
        NavService = navigationService;
    }

    /// other properties, such as CustomPins

    private INavigationService _navService = null;
    public INavigationService NavService
    {
        get { return _navService; }
        set { SetProperty<INavigationService>(ref _navService, value); }
    }

    /// other code is here
}

And now the XAML:


    <view:CustomMap x:Name="cusmap"
IsShowingUser="True" MapType="Street"
CustomPins="{Binding CustomPins, Mode=TwoWay}"
NavigationService="{Binding NavService}" />

And now we can get use the navigation service from our CustomMapRenderer like this by adding in our InfoWindowClick handler. Remember that we wired it up in the OnMapReady function. Now let’s put some functionality in the handler:


private void OnMapInfoWindowClick(object sender, GoogleMap.InfoWindowClickEventArgs e)
{
    if (_customMap.NavigationService != null)
    {
        _customMap.NavigationService.NavigateAsync(DevDaysSpeakers.PageKeys.Speakers);
    }
}

You can find all of this code in my GitHub repo in the MapRenderer solution. If you run the project, you can tap on the “Map” button on the main page. It will bring up the map and display a marker. If you tap the test button, it will update the marker to a new location. Tapping on the marker will show a custom info window, and tapping that window will use the Prism navigation service to navigate back to the main page.

Sounds like I am finally going to pick up a Mac laptop, so I should be able to expand these posts to the iOS platform. Looking forward to that.

Lots of stuff! Hope you find some of it useful.

Custom Map Renderer on Android: Part 2

In the previous post, we setup our DevDaysSpeakers app to include a page that displays a map. To get the map to display our information, we have a few things we have to do. Let’s start with subclassing the Xamarin Forms Map class with our own class and create our own pin data object.


public class CustomPin
{
    public Pin Pin{ get; set; }
    public int Id { get; set; }
    public string Url { get; set; }
}

public class CustomMap : Map
{
    public List<CustomPin> CustomPins { get; set; }
}

And now we will use our new CustomMap class in our XAML. Make sure that you have the namespace declared (see view namespace below) and then you declare it as below. Note that I am just using some of the properties that are declared in the base Map class.


<?xml version="1.0" encoding="utf-8" ?>
<ContentPage
    xmlns="http://xamarin.com/schemas/2014/forms"
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
    xmlns:view="clr-namespace:DevDaysSpeakers.View"
    xmlns:prism="clr-namespace:Prism.Mvvm;assembly=Prism.Forms"
    prism:ViewModelLocator.AutowireViewModel="True"
    xmlns:maps="clr-namespace:Xamarin.Forms.Maps;assembly=Xamarin.Forms.Maps"
    Title="Map"
    x:Class="DevDaysSpeakers.View.MapPage">
    <Grid>
        <!-- lets reference our custom map now -->
        <view:CustomMap x:Name="cusmap"
            IsShowingUser="True"
            MapType="Street" />
    </Grid>
</ContentPage>

So if we were to run the app at this point, we would see the exact same thing as before. To add the custom behavior, we need to add in our custom map renderer in the Android project. So let’s get started.

In our droid project, let’s create a new class called CustomMapRenderer in the root of the project. The very first thing that we see is that we have to decorate the code at the namespace level to tell Xamarin that whenever we see the CustomMap class in our shared XAML, we should implement using this class. It will look like the following:


/// usings are here

[assembly: ExportRenderer(typeof(DevDaySpeakers.View.CustomMap), typeof(DevDaySpeakers.Droid.CustomMapRenderer)]
namespace DevDaySpeakers.Droid
{
    public class CustomMapRenderer : MapRenderer, GoogleMap.IInfoWindowAdapter, IOnMapReadyCallback
    {
        /// ... implementation
    }
}

Included above is the class declaration and you can see that it derives from MapRenderer class and implements a pair of interfaces that are used to display the map in Android.

In the CustomMapRenderer, we want to keep track of a couple of instances, the first being our subclasssed Map (CustomMap) and the actual GoogleMap object is in Android. These objects are picked up in a couple of different places.

First, the CustomMap object is captured when the CustomMapRenderer instance is assigned and you can capture that by overriding OnElementChanged. You also use this method to clean up your wired up event handler for when a user taps on the info window associated with a map marker.

Secondly, in our implementation of the IOnMapReadyCallback interface, our implementation of the OnMapReady function saves the instance of the GoogleMap.


/// usings are here

[assembly: ExportRenderer(typeof(View.CustomMap), typeof(Droid.CustomMapRenderer)]
namespace DevDaySpeakers.Droid
{
    public class CustomMapRenderer : MapRenderer, GoogleMap.IInfoWindowAdapter, IOnMapReadyCallback
    {
        private GoogleMap _map = null;
        private DevDaySpeakers.View.CustomMap _customMap = null;

        protected override void OnElementChanged(ElementChangedEventArgs<Map> e)
        {
            base.OnElementChanged(e);
            if (e.OldElement != null)
            {
                // remove the event handler for the info window tap
                _map.InfoWindowClick -= OnMapInfoWindowClick;
            }

            if (e.NewElement != null)
            {
                // save reference to the CustomMap that was
                // in the XAML declaration
                _customMap  = (View.CustomMap) e.NewElement;
                ((MapView) Control).GetMapAsync(this);
            }
        }

        public void OnMapReady(GoogleMap googleMap)
        {
            /// called when the GoogleMap is ready, we need to save the
            /// instance, wire up the event handler for the info window tap,
            /// tell the map to use this class for handling the info window
            /// and finally load the markers.
            _map = googleMap;
            _map.InfoWindowClick += OnMapInfoWindowClick;
            _map.SetInfoWindowAdapter(this);

            /// load the pins
            UpdatePins();
        }

        private void OnMapInfoWindowClick(object s, GoogleMap.InfoWindowClickEventArgs e)
        {
            // event handler stub
        }

        public Android.Views.View GetInfoContents(Marker marker)
        {
            /// for GoogleMap.IInfoWindowAdapter implementation
            /// will just do default
            return null;
        }

        public Android.Views.View GetInfoWindow(Marker marker)
        {
            /// for GoogleMap.IInfoWindowAdapter implementation
            /// will just do default
            return null;
        }

        private void UpdatePins()
        {
            /// stub for updating pins on the map
        }
    }
}

Most of that is pretty straight forward I think. We are implementing our interfaces and saving instances to the Map objects so that we can use them later. We are also wiring up the event handler so that can capture when the user taps the information window that appears after tapping on a map marker.

Next we will handle adding the pins to the map by implementing the UpdatePins method. The interesting thing in this is that our CustomMap instance (_customMap) contains the business data of the app, while the GoogleMap (_map) instance does all the presentation.


private void UpdatePins()
{
    if (_map == null)
        return;

    _map.Clear();
    foreach (var pin in _customMap.CustomPins)
    {
        var marker = new MarkerOptions();
        marker.SetPosition(
            new LatLng(pin.Pin.Position.Latitude,
            pin.Pin.Position.Longitude));
        marker.SetTitle(pin.Pin.Label);
        marker.SetAddress(pin.Pin.Address);
        marker.SetIcon(BitmapDescriptorFactory.DefaultMarker(210));
        _map.AddMarker(marker);
    }
}

From above you can see that we are creating markers, setting the title property and the address property, and also changing the look of the pin itself. In this case we are only changing the color from default to blue. But you can also add in your own bitmaps if you want.

Let’s talk a bit about customizing the info window. In case you aren’t sure about the info window, this is what is pop’d up on the map when you tap on the marker. We have the ability to customize it and this happens in the GetInfoContents method in the code fragment above. By returning null, you will just get the default contents.

If you want to do something custom, you will need to define your own layout in the Resources\layout namespace. If you look at the sample code, there is nothing special there, I simply used some random template I saw somewhere to learn some syntax and made one. I am more familiar with XAML and just tried to match up the containers and controls.

But to me, the more important code is overriding the GetInfoContents method to put useful information in the popup.

public Android.Views.View GetInfoContents(Marker marker
{
    var inflater =
        Android.App.Application.Context.GetSystemService(Context.LayoutInflaterService)
        as Android.Views.LayoutInflater;

    if (inflater != null)
    {
        Android.Views.View view = null;
        var pin = GetCustomPin(marker);
        if (pin != null)
        {
            view = inflater.Inflate(Resource.Layout.CustomInfoWindow, null);

            // find the controls in the layout for the title and subtitle.
            // if we find them, we can populate them with our own info
            var infoTitle = view.FindViewById<TextView>(Resource.Id.InfoWindowTitle);
            var infoSubTitle = view.FindViewById<TextView>(Resource.Id.InfoWindowSubtitle);

            if (infoTitle != null)
                infoTitle.Text = pin.Pin.Label;

            if (infoSubTitle != null)
                infoSubTitle.Text = pin.Pin.Address;

            return view;
        }
    }

    return null;
}

At this point, if the map were to load up, we should see a pin on the map and be able to tap on it, and show some of our own custom information.

Next, we will talk about how to update the map, and better, do it from the view model.

Xamarin Dev Days Lab – Prism Step 4

Well, hello from Las Vegas! I am down in LV for the Autodesk Developer Network Dev Days and the Autodesk University. It’s a pretty fun time, especially if you are involved in engineering or CAD of any kind. If you are like me, also a dev person, there is lots of cloud stuff to add in there. And now even virtual reality and augmented reality to geek out!

In any event, travel makes for weird schedules and time awake. So here I am working on navigation in Xamarin Forms projects. But first a little recap: in our last post we really dug into dependency injection and showed the power of it. We saw some concrete examples of how it can make our app better architected, and how that makes it more maintainable. Next we will take that architecture to the next level and add in navigation. You probably remember from the start of the app how we had to register pages for navigation: let’s review that.

In a normal Xamarin app, the navigation system is accessed via a singleton object. To navigate to another page , you have to provide the actual page type of the destination page to the navigation service. Right away, you can see that this could be a headache in the future: if you change the page type, you need to change it everywhere in your app that the page is referenced. Yuck. And what if you have needs that are a bit more dynamic? For example, you could have a free version of an app and a paid version. In that case your dependencies just increased by a factor of …? Well, it depends on the app, but every time you have to make that decision in your app is another level of complexity. Instead, wouldn’t it be cool if you could just determine if the app was paid or not and navigate to the appropriate page based on that status?

Prism provides a better model for navigation. Not only does Prism remove the dependency on types, it also moves the navigation brains up to the view model (where the business logic is) and away from the presentation level (where the Xamarin navigation system resides). And this all begins in the RegisterTypes method of the App object. So let’s start with what we have there.


/// first we have the register types
protected override void RegisterTypes()
{
    // non nav registration here
    Container.RegisterTypeForNavigation
        <View.SpeakersPage, ViewModel.SpeakersViewModel>();
}

/// and our initial navigation
protected override void OnInitialize()
{
    NavigationService.NavigateAsync("SpeakersPage");
}

The above registers the SpeakersPagae for navigation and associates it with the SpeakersViewModel. There is also an optional parameter in the call to associate the registration with a key. Since we didn’t provide a key, Prism made one for us based on the name of the page. When you call NavigateAsync, you provide the key and the Prism navigation system looks up what is associated with the key and instantiates the appropriate page and view model.
We can improve this by specifying our own key. If we do that, in every place we navigate to the page, simply changing the initial registration will allow us to put in a different page. We won’t have to go to every place and change the call. I like to create a static class with the page keys so that I can reduce my use of magic strings.

public static class PageKeys
{
    public const string Speakers = "speakers";
    public const string Details = "details";
}

And now we can update the two functions above:


protected override void RegisterTypes()
{
    // non nav stuff here

    Container.RegisterTypeForNavigation
        <View.SpeakersPage, ViewModel.SpeakersViewModel>
        (PageKeys.Speakers);
}

protected override void OnInitialize()
{
    NavigationService.NavigateAsync(PageKeys.Speakers);
}

 
So that is looking pretty cool. Let’s pretend there is a paid and free version of the app and adjust our registration:

protected override void RegisterTypes()
{
   if (IsPaidApp)
   {
        Container.RegisterTypeForNavigation
          <View.SpeakersExPage, ViewModel.SpeakersExViewModel>
          (PageKeys.Speakers);
   }
   else
   {
       Container.RegisterTypeForNavigation
         <View.SpeakersPage, ViewModel.SpeakersViewModel>
         (PageKeys.Speakers);
   }
}

Awesome! Just by using the key instead of the page type name, we made our app even more flexible and easier to maintain. None of our in app navigation will change, we always just call:


NavigationService.NavigateAsync(PageKeys.Speakers);

What else is important in this? Well I mentioned this before, but the navigation system is rooted into the presentation layer of the code. But navigation is really about business logic. The Prism navigation service abstracts out the presentation and the service is passed around as an interface. For unit testing of your view model, you can mock the interface and your view model won’t know or care.

You probably already know how the view model gets the navigation service (dependency injection, constructor parameter), but just in case it is late or you don’t remember every single detail of the previous posts, we just put the dependency into the constructor and the dependency injection container injects it for us. You can see this in the code. If you are looking at the code and saying: wait, INavigationService is not registered anywhere in your code, you are right. The App base class does it for us because they assumed that you were going to want that service. Dig into the Prism code if you want to find out more.

The last thing I want to bring up with respect to Prism navigation is how to pass data during navigation. When you use the NavigationService.NavigateAsync method, the second parameter is a NavigationParameters object, and you can pass pretty much anything in in. Let’s dive in.

In this example, I want to know when the SpeakersPage is navigated to the first time. So in the app object, I am going to add that parameter to the initial navigation in the OnInitialize method.


protected override void OnInitialize()
{
    var nps = new NavigationParameters();
    nps.Add("first", true);
    NavigationService.NavigateAsync(PageKeys.Speakers, nps);
}

How do we consume this data? And where do we consume it? This data is really business logic data so we want to consume it in the view model. To get the data up to the view model we have to have our view model implement the INavigationAware interface. This interface has two methods: OnNavigatedFrom and OnNavigatedTo. I normally like to implement this in the BaseViewModel class so that all the view models have it already and I can also setup some generic functionality if I want.

public class BaseViewModel : BindableBase, INavigationAware
{
    /// ... other base stuff goes here

    public virtual void OnNavigatedFrom(
        NavigationParameters nps)
    {
    }

    public virtual void OnNavigatedTo(
        NavigationParameters nps)
    {
    }
}

So now in my SpeakersViewModel, I will override the OnNavigatedTo method to implement looking for first run:

public class SpeakersViewModel : BaseViewModel
{
    /// ... existing stuff here

    public override void OnNavigatedTo(
        NavigationParameters nps)
    {
        base.OnNavigatedTo(nps);

        if (nps == null || !nps.ContainsKey("first"))
            return;

        bool firstLoad = (bool) nps["first"];
        if (firstLoad)
        {
            /// do first functionality here
        }
        else
        {
            /// do something else
        }
    }
}

But how does that actually work? What happens is that the navigation service is aware of the page creation. And as part of the page creation, we know that the view model will be automatically injected. The navigation service will look at the view model object that was injected and see if it implements the INavigationAware interface. If it does, it will call the OnNavigatedTo method. More awesomeness!

Well, that is it for navigation. You can see full-on code at the usual place in my GitHub repo under Step 04.
Enjoy!

Xamarin Dev Days Lab – Prism Step 3

Introduction

In our last post, we set up the view model for the SpeakersPage and made use of the built in view model functionality included in Prism. We setup a base view model for our app to contain common functionality. The SpeakersViewModel class has the implementation code for retrieving the list of speakers embedded in the view model itself. Fine for a demo, but in a real app, we would be better served by moving this functionality out and using it via an interface. By implementing the functionality as an interface, we will be able to reuse the code in other view models. Since the SpeakersPageViewModel only knows it via the interface, we will also be able to mock the service with known values for use in unit tests, without changing the view model. And we can use the Prism framework and the dependency injection that is built in to make this easier. So lets take a look at this.

The Interface

The first thing we want to do is look at the functionality that is currently in our view model class. All it is doing is calling a web api to return a list of speakers. That seems pretty straight forward. Let’s start our interface with that:


public interface ISpeakersService
{
    Task<List<Speaker> GetAllSpeakersAsync();
}

Implementing will be easy: we already have all the code that we need in the view model from the demo app:


public class SpeakersService : ISpeakersService
{
    public async Task<List<Speaker>> GetAllSpeakersAsync()
    {
        using (var client = new HttpClient())
        {
            //grab json from server
            var json = await client.GetStringAsync(
                "http://demo4404797.mockable.io/speakers");

             //Deserialize json
             var items =
                JsonConvert.DeserializeObject<List<Speaker>>(json);
             return items;
        }
    }
}

//

From above, you can see that we have just moved all of the implementation code from the view model into a separate service object. So how do we start using this new code in our SpeakersViewModel?
The first thing we need to do is register this service in our App object. Remember that we are registering via an interface: this means we can change out the implementation at any time.
Here is the RegisterTypes function in the App object updated to register the service:


protected override void RegisterTypes()
{
    Container.RegisterType
        <Services.ISpeakersService, Services.SpeakersService>();
    Container.RegisterTypeForNavigation
        <View.SpeakersPage, ViewModel.SpeakersViewModel>();
}

Next we need to refactor the SpeakersViewModel: we will add the interface to the view model constructor and change the GetSpeakersAsync to call the interface to retrieve the speakers data:


public class SpeakersViewModel : BaseViewModel
{
    private Services.ISpeakersService _speakersService = null;

    public SpeakersViewModel(Services.ISpeakersService speakersService)
        : base()
    {
        _speakersService = speakersService;
    }

    /// other parts of the view model go here
    /// now lets look at GetSpeakers ...
    private async Task GetSpeakers()
    {
        if (IsBusy)
            return;

        Exception error = null;
        try
        {
            IsBusy = true;

            var items =
                await _speakersService.GetAllSpeakersAsync();
            Speakers.Clear();

            foreach (var item in items)
                Speakers.Add(item);
        }
        catch (Exception ex)
        {
            error = ex;
        }
        finally
        {
            IsBusy = false;
        }

        if (error != null)
            await Application.Current.MainPage.DisplayAlert(
                "Error!",
                error.Message,
                "OK");
    }

}

So what do we have above? All of a sudden the ViewModel has a dependency on ISpeakersService. But we weren’t creating the view model in the first place: instead, Prism and the AutoWireViewModel attached property (see the previous blog post) are creating the view model for us and attaching it to the page. When Prism does this, it uses the container that was selected (step 01 blog) to create the view model and all the dependencies that are required for the view model, and it does this via reflection and then looking at what you specified in the App.RegisterTypes method. I hope that you can see that you can change up the implementation details of the interface without ever affecting the view model itself. You can even unit test your view model by mocking the service.

Now the view model just makes a call to retrieve the speakers. It has no idea if the speaker are read from a web api, a database, a file or even from memory! It just knows to make the call and it will get the data.

I really want to emphasize this: the view model knows nothing. It has no dependency on any implementation and you can change that around as you see fit! In fact, I am going to change the code of the SpeakersService implementation. I captured the json payload that was returned from the web api and saved it as a constant in the implementation. Now instead of calling out to the web api, I just return the json payload directly, and now for testing, everything is much quicker. And as mentioned earlier, using these known values, I can use this implementation for unit testing of the view model.


public class SpeakersService : ISpeakersService
{
    /// you can see this actual string value in the GitHub repo
    /// under step 03
    private const string JsonResponse =
        "...json response string captured from web api";

    public async Task<List<Speaker>> GetAllSpeakersAsync()
    {
        var items =
            JsonConvert.DeserializeObject<List<Speaker>>(JsonResponse);
        return items;
    }
}

Recap

We have taken the next step in making the dev days app a little more production worthy. We took out the implementation of our speakers service away from the view model, defined it as an interface and injected that into our view model. We used the dependency injection that is built into Prism to inject the implementation of the service into the view model. And then for fun (and quicker testing), we changed the implementation of the interface to serve up the results from a json payload that had been captured previously. Now we can do testing much quicker.

All of this code can be found in the Step03 portion of the repository. Make sure you check out the two different implementations of ISpeakersService contained in the SpeakersService.cs file and how they could be registered in App.cs.

The next step will be to add navigation to the app so we can see the details of a selected speaker.

XamarinDevDays Vancouver Recap

Hello everyone, just a small follow up on the event yesterday. It was a nice introduction to Xamarin, and we were well led by the presentation team of Mark Schramm (@markbschramm), Adrian Stevens (@Adrian_stevens), Jan Hannemann (@bitdisaster) and Sergiy Baydachnyy (@sbaidachni).

Presentations from Adrian, Jan and Sergiy preceded lunch (thanks Microsoft) and afterwards, Adrian led us through a sample app using Xamarin Forms. If you want a quick introduction to Xamarin Forms development, head over to the dev days GitHub repo (https://github.com//xamarin/dev-days-labs) and follow the hands on lab. It is a pretty good introduction.

For my part, I am going to turn that app into a series of blog posts on using the Prism framework. So keep your eyes open for that.

Enjoy your Sunday!