Xamarin Forms Navigation: Part 3 – MVVM and the MasterDetailPage

In Part 2, I created a pattern where I could use the MVVM pattern to manage the navigation on a TabbedPage. Though there are 5 patterns of navigation outlined in Xamarin.Forms, really only the TabbedPage, MasterDetailPage, and Carousel seem to fit the bill for how to handle the main form of navigation. The others are more concerned with navigation from summary to detail and can be used in conjunction with the previously mentioned three.

In essence, the TabbedPage, MasterDetailPage, and Carousel are all representations of the same root data (a collection of pages, and a selected page) much like a ListView or Picker control. That being said, I knew that once I settled on the TabbedPage as the main UI navigation mechanic, that I’d have some users (one in particular) suggesting that they’d prefer something more akin to the MasterDetailPage (which I had started with in Part 1). This led me to work on MVVM-ing the MasterDetailPage for use with the same ViewModel I used for the TabbedPage in Part 2.

This isn’t the complete story for making this fully MVVM Style (the headers aren’t working and I haven’t added icons or fancy formatting), but it gives things a good start. And, the same as in Part 2, I can now set which tab is currently selected by setting

CurrentTab = Tabs[1]; 

in the ViewModel’s constructor if I like… and write the appropriate tests to ensure that whatever tab I want selected has been selected.

View

<?xml version="1.0" encoding="utf-8" ?>
<MasterDetailPage xmlns="http://xamarin.com/schemas/2014/forms"
 xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
 x:Class="MyProject.MasterDetailRootPage" 
 Title="Master Page!!" 
 CurrentPage="{Binding CurrentTab}">
 <MasterDetailPage.Master Title="Master Page">
    <ContentPage Title="Not Displayed">
        <ListView ItemsSource="{Binding Tabs}" SelectedItem="{Binding CurrentTab}">
            <ListView.ItemTemplate>
                <DataTemplate>
                    <ViewCell>
                        <ViewCell.View>
                            <StackLayout Orientation="Horizontal">
                                <Label Text="{Binding Title}" />
                            </StackLayout>
                        </ViewCell.View>
                    </ViewCell>
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>
    </ContentPage>
</MasterDetailPage.Master>
</MasterDetailPage>

CodeBehind

 public partial class MasterDetailRootPage : MasterDetailPage {
     public static readonly BindableProperty CurrentPageProperty = BindableProperty.Create<MasterDetailRootPage, Page>(x => x.CurrentPage, null, BindingMode.TwoWay, propertyChanged: OnItemsSourcePropertyChanged);

     public MasterDetailRootPage() {
         InitializeComponent();
     }

     Page CurrentPage { get; set; }

     static void OnItemsSourcePropertyChanged(BindableObject bindable, Page value, Page newValue) {
         var masterDetailPage = (MasterDetailRootPage)bindable;
         masterDetailPage.Detail = newValue;
     }
 }

ViewModel (same as was used in Part 2)

public class RootPageViewController : ViewModelBase { 
    INavigableTabBuilder tabBuilder; 
    Page currentTab; 
    ObservableCollection<Page> tabs; 

    public RootPageViewController(INavigableTabBuilder tabBuilder) { 
        this.tabBuilder = tabBuilder; 
    } 

    public ObservableCollection<Page> Tabs { 
        get { return tabs ?? (tabs = new ObservableCollection<Page> { 
            tabBuilder.CreateFirstTab(), tabBuilder.CreateSecondTab(), }); 
        }
        private set { SetProperty(ref tabs, value); } } 

    public Page CurrentTab { 
        get { return currentTab ?? (currentTab = Tabs[0]); } 
        set { SetProperty(ref currentTab, value); } 
    }
}

Xamarin Forms Navigation: Part 2 – MVVM and the TabbedPage

In Part 1 I discussed that I had settled on using the TabbedPage for navigation within my application. Like the MasterDetailPage, the TabbedPage lacks the ability to bind to the properties of its viewmodel to follow the MVVM pattern out of the box. I was, though, able to find an example of a BindablePicker that gave me all the tooling I needed to create my own.

View

<?xml version="1.0" encoding="utf-8" ?>
<TabbedPage xmlns="http://xamarin.com/schemas/2014/forms"             
            xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" 
            x:Class="MyProject.RootPage"
            Children="{Binding Tabs}"
            SelectedItem="{Binding CurrentTab, Mode=TwoWay}">
</TabbedPage>

CodeBehind

public partial class RootPage : TabbedPage {
    public static readonly BindableProperty ChildrenProperty = BindableProperty.Create<RootPage, IEnumerable>(x => x.Children, null, BindingMode.TwoWay, propertyChanged: OnItemsSourcePropertyChanged);

    public RootPage() {
        InitializeComponent();
    }

    public new IEnumerable<Page> Children {
        get { return base.Children; }
        set { SetValue(ChildrenProperty, value); }
    }

    private static void OnItemsSourcePropertyChanged(BindableObject bindable, IEnumerable value, IEnumerable newValue) {
        var tabbedPage = (TabbedPage)bindable;
        var notifyCollection = newValue as INotifyCollectionChanged;
        if (notifyCollection != null) {
            notifyCollection.CollectionChanged += (sender, args) => {
                if (args.NewItems != null) {
                    foreach (var newItem in args.NewItems) {
                        tabbedPage.Children.Add((Page)newItem);
                    }
                }
                if (args.OldItems != null) {
                    foreach (var oldItem in args.OldItems) {
                        tabbedPage.Children.Remove((Page)oldItem);
                    }
                }
            };
        }

        if (newValue == null) return;

        tabbedPage.Children.Clear();

        foreach (var item in newValue) tabbedPage.Children.Add((Page)item);
    }
}

ViewModel

public class RootPageViewController : ViewModelBase { 
    INavigableTabBuilder tabBuilder; 
    Page currentTab; 
    ObservableCollection<Page> tabs; 

    public RootPageViewController(INavigableTabBuilder tabBuilder) { 
        this.tabBuilder = tabBuilder; 
    } 

    public ObservableCollection<Page> Tabs { 
        get { return tabs ?? (tabs = new ObservableCollection<Page> { 
            tabBuilder.CreateFirstTab(), tabBuilder.CreateSecondTab(), }); 
        }
        private set { SetProperty(ref tabs, value); } } 

    public Page CurrentTab { 
        get { return currentTab ?? (currentTab = Tabs[0]); } 
        set { SetProperty(ref currentTab, value); } 
    }
}

Because of the two-way binding, I can now set which tab is currently selected by setting

CurrentTab = Tabs[1]; 

in the ViewModel’s constructor if I like… and write the appropriate tests to ensure that whatever tab I want selected has been selected.

Here we go…

 

Xamarin Forms Navigation: Part 1 – Navigation is HARD!

Navigation patterns in a cross-platform environment is difficult because the heuristics of each platform are simply not the same. When trying to achieve a single-implementation for all platforms, you end up being in a bit of a conundrum.

The Xamarin.Forms page navigation experience is somewhat limited, though I think that is because of the hindrance of trying to be all things to all platforms. Hierarchical navigation between pages, using the NavigationPage, seems to be fairly common and I didn’t have much issue with settling on it as a mechanism to navigate from summary to detailed views of data but that didn’t resolve the question of how I would like people to be able to navigate the different aspects of the application.

At first I was excited to use MasterDetail Page Navigation Recipe but it didn’t allow me to adhere to a strict MVVM pattern straight out of the box. Upon further investigation I found that the common term for this navigation pattern is a “Hamburger Menu”, and it has quite a history. Due to its history, there has been a lot of discussion about the problems with it (Louie A. has a fantastic synopsis here). I believe that Carousel also suffers from a lack of discoverability so that left me with deciding on the NavigationPage and TabbedPage which can be used together.

Here we go…

Week Four: A Microsoft Developer’s Introduction to Xamarin and Cross-Platform Development

This was a week of humbling frustration for me. I didn’t get much, or much consecutive, time to work on achieving the goals laid out in Week 2. The VPs of the companies I support were preparing for meetings that often require some analytics that they task me to accomplish in a short amount of time. There are a few learnings, though, I’d like to share:

  1. We FINALLY got our D-U-N-S number. I was, incorrectly, told that all we needed to do was send an email to Dun & Bradstreet to initiate the process. Turns out, when you register your email with Apple, you can then request a D-U-N-S number. That turned out to be the fast path and we ended up getting our number late Friday afternoon.
  2. From a coding perspective, I was intrigued by pulling in device information to enable my app to include this in crash reporting and such if the case came that I wanted to be able to perform the same functionality as Insights or HockeyApp (coincidentally, now both owned by Microsoft). I am glad I went down this road as I am not sure what the future holds for either of those features as they both do rather the same thing and with different pricing models.

What I messed up with here was that I created a folder called “System” to report on System information. This caused a LOT of errors and I couldn’t compile the application, nor deploy it to the emulator. It took a back-and-forth with the support staff at Xamarin (thanks Jimmy G.!) to figure out what was going on. This was quite humbling. I still feel that it was a bug in this area because, using the fully qualified namespace for the classes should not cause confusion for the compiler to determine the difference between System.CodeDom.Compiler.GeneratedCodeAttribute and my class defined in MyApp.System.MyClass but it is what it is. I renamed my folder to SystemInformation and away we go.

The other learning in this area is the Visual Studio will display a number of “Errors” but yet the application will still compile and run successfully on the emulator or physical device. This is disconcerting because I have never had apps that compile when there are errors listed.

For example, I am using XAML Forms for my user interface. Apparently the error: “The name ‘InitializeComponent’ does not exist in the current context” is not actually an error but, rather, a warning.

screenshot

In my experience it can either mean that your XAML view is not an embedded resource or it can mean nothing; carry on wayward son. This is hugely frustrating because I am not used to seeing errors and having them a) not mean anything, and b) not provide clear information as to how to resolve the issue.

 

 

Either way, I was able to accomplish the “Set up solution for Unit and UI Testing” and (newly added) “Collect Device Information for Crash Reporting” tasks from week 2. Now that we have our D-U-N-S number, we should be able to get set up with continuous integration and start to see some iOS features of the application.

 

Week Three: A Microsoft Developer’s Introduction to Xamarin and Cross-Platform Development

So, from the task list I put together in  Week Two: A Microsoft Developer’s Introduction to Xamarin and Cross-Platform Development, I was able to accomplish the Push Notifications and Unit/UI Testing tasks. I was also able to get Xamarin Insights working with the bootstrapping aspect of the application. It works slightly differently on iOS than Android so I wanted to get initialization complete on each platform rather than in a common solution.

Getting this working lead me to think that building your own Insights-like functionality really wouldn’t be that hard as long as you knew where to go to collect the kinds of information that you were interested in. I went on a short detour into investigating the ACR.DeviceInfo package. It really does help get nearly as much information about the device being used as the Xamarin Insights application does. You’d really only need to build your own API to collect the data et voilà, you have your own, custom, Insights-like application sans the IDE integration. I left off with this on Friday and didn’t have time to quite implement it the way I had wanted. I hope to have something up and working here early this week.

 

Week Two: A Microsoft Developer’s Introduction to Xamarin and Cross-Platform Development

In week 1 I mentioned that Xamarin Studio on Windows was not great. Fortunately, as I’ve been working more with it, Visual Studio is a more than competent alternative. Additionally (and I have been waiting for/predicting this for some time now), Microsoft’s intent to purchase Xamarin has been announced. I think this is fantastic news.

I’d guess that Xamarin licensing will roll into MSDN subscriptions and Xamarin developers will likely be given discounted MSDN subscription options but we shall see. The marketing/transition folks will end up taking care of that over the next year or so. It should be a fun ride.

Onto real development:

I didn’t get much time to actually work on the scaffolding for my first application but what time I did get was significantly enhanced by reading through Jonathan Yates‘ page, Adventures in Xamarin Forms. The articles, along with the accompanying source code for the Mountain Weather application are well written and helped me get going more quickly. I have a history developing WPF applications. This helped me start to feel that I wasn’t entering into an alien environment while developing a Xamarin.Forms style application.

All that being said, here is the list of scaffolding tasks (in no particular order) that I wanted to accomplish to 1) feel comfortable with the platform, and 2) have knowledge of before actually trying to develop operational (versus technical) business value:

Set up Solution to maximize Code Re-Use From Week 1 – My preference is to use the “Blank App (Xamarin Forms Portable)” template
Implement IoC Container I really liked how Jonathan Yates implemented this in his Mountain Weather application
Add Application Localization This was pretty easy and familiar with how I’ve done things in WPF applicaitons in the past. There is a good article to follow if you haven’t done this before, but I didn’t find it all that necessary.
Set up MVVM Infrastructure I desire my applications to be testable. Coming from the WPF background, I’m familiar with the MVVM pattern and, because the Xamarin.Forms applications are Xaml-based, this was a natural fit. Again, the Mountain Weather application was helpful with getting this implemented.
Set up solution for Unit and UI Testing This is still coming (maybe even as early as today) but there are enough samples to follow. I don’t foresee this being problematic.
Set up Continuous Integration This one kinda irks me. You’re kind of painted into a corner here because of the “Apple problem” – To build iOS applications, they must be compiled on Apple hardware. Also, you have to be a registered Apple developer. This has two problems: 1) We don’t have an OSX machine in-house yet so I don’t know of a way around setting up a build machine until after we purchase one. I’m trying to put off committing to Apple purchases for as long as possible. 2) To become an Apple developer, you have to not only pay your money but, if you are a company wanting to develop application, you have to apply for a “D-U-N-S” (I don’t think it’s coincidental that this could be pronounced “dunce”) number. This is a number given to you by an “Apple Approved” business registry. We emailed away for this a week ago. It’s said that this takes up to a week. It’s free, but forcing people to subscribe to this particular US business registry is just another of those “prescriptive” things that gets under a person’s skin.
Set up Application Updating After they are deployed, I’d like to be able to have my applications update themselves. There is a Xamarin article on how to do this. I don’t know a lot of this process so I’d like to understand it and have it working. There are two separate processes: one for iOS and one for Android.
Set up application to support UI Themes I support a number of companies with the applications that I build. Though each application has the same heart, the look of each is often branded to fit each individual company. I came across an article entitled, Xamarin: Skinning an app for different clients using Appearance and themes from Andrew Ross that I intend to use as a starting point for implementation of implementing a different theme for each company.
Set up solution for Unit and UI Testing This is still coming (maybe even as early as today) but there are enough samples to follow. I don’t foresee this being problematic.
Mobile Sync I don’t expect my application to live in an “always connected” state. The data being entered should be able to be synced back to mothership once a reliable connection has been established. I have found a number of articles that I intend to use to help get me started here:

Support Push Notifications As was the case with application updating, the process for this appears to be different between iOs and Android.
Application Authentication/Identity I’m not completely sure how this one will go. I have the scenario where I would like the same authentication experience for both our AD users as well as our external clients. I’d like whatever process that is used here to support multi-factor authentication as well as self-serve account maintenance. I am leaning toward leaning on Azure Mobile Services again here where, again, it seems there may be a difference in how to handle this in iOS versus Android.

That’s all for this week.

Getting Started: A Microsoft Developer’s Introduction to Xamarin and Cross-Platform Development

In investigating the creation of mobile applications, it was appealing to me to be able to leverage at least a little of my knowledge of .NET and the tooling that I am familiar with in order to take the fast-track to delivering business value as quickly as possible. Xamarin seemed to me (then and even still) to be the right choice for the job.

I have been developing with this platform now for a couple of weeks though, to be honest, the first week I didn’t have very much time to devote to it. It’s only now, nearing the end of my second week, that I feel like I truly have a grasp of the basics and am starting to get some headway. Here are some of the revelations, in plain language, that I have found so far:

Xamarin Studio for Windows is Teh Suck!

The editor itself likely isn’t terrible. It’s the tooling within that is different that is really quite terrible. I have always struggled with project templates provided both within Visual Studio but now, also, with Xamarin Studio. I find that many of the project templates either add more than advertised and I have to spend the first bit of development removing unwanted code or features much like a new mobile phone where you have to remove your carrier’s pre-installed and unwanted software.

The kicker here was that, if you are using Xamarin Studio on Windows, it does not allow you to create iOS projects. The support rep and developer support I had were saying something or other about licensing and whatnot. The fact is, I wasted an entire day trying to figure out what project template to use to create a default application to do both iOS and Android development. It isn’t there. Don’t bother looking.

Here’s the template I ended up going with in Visual Studio to create the expected projects:

screenshot

Really, the project I should have chosen was Xamarin.Foms Portable. This forum thread explains it but when you are starting out, it’s not very clear.

Strange Project Folder Structures/Project Types

Instead, if you create a project using the templates included in Visual Studio, you can create a Xamarin.Forms application and it will create three projects for you:

  1. A “Droid” project (named like <project name>.Droid)
  2. An “iOS” project (named like <project name>.iOS)
  3. and a “shared” project (named like <project name>)

screenshot

I’m not really sure what kind of project that App1 project is. It’s not a Portable Class Library (PCL); you can’t add references to other projects within your solution with it. Both the .Droid and .iOS projects have references to it. It’s not really clear to me what it is. I have yet to find the documentation on what the “double diamond” project type is. I found a good resource on AdventuresInXamarinForms.com and it’s related sample application’s source code on github. It didn’t use the “double diamond” project type and it’s project structure was more akin to how I prefer to set up my applications. So, I ditched good ol’ double-diamond and replicated everything in there with a plain PCL library. Worked good.

I mentioned the folder structure. That, too, wasn’t what I prefer. I don’t blame Xamarin for this. This has been a struggle of mine for years even within Visual Studio.

I have (roughly) followed JP Boodhoo’s Directory Structure for Projects for a number of years now. It’s served me well. The default template (surprise) does not follow this structure so I end up wasting time removing projects, moving them to the folder I want, adding existing project in Visual Studio (or manually editing the .sln file) to get everything set up the way I like it. It’s a waste of time and I wish that the templated projects would ask me where I want to put each project on the file system but it doesn’t. Not for Xamarin or Visual Studio.

So, if you have a preferred organization for your projects, expect to spend time monkeying with things here.

Don’t Assume I am Using Xamarin Studio on a Mac

The documentation on Xamarin.com as well as the developer rep I had assigned to help me all (I don’t want to say “all”… let’s go with NEARLY all) assume you are using Xamarin Studio on a Mac. It’s advertised that you can do your development within Visual Studio. Knowing that that is my scenario, I wish that the developer rep I was assigned was more familiar with that scenario as there is slightly different tooling. I also wish the documentation allowed you to switch scenarios like how you can switch languages when reading MSDN documentation to suit your situation and even compare how things are different.

Take A Look At Our Sample Apps… If you can

The support rep listened to what I wanted to accomplish and sent me links to a bunch of documentation and sample apps to help get me going quickly. The app that had the most features in a way that I wanted to use them was their Sport app. I downloaded it and tried to compile it without success. After sending in a support request to try and figure out why, I was told it was an issue with Visual Studio and code completion. I was supposed to downgrade my version of Xamarin to a previous version (what a way to kill the thrill of doing your first mobile application. You see it as leading edge and exciting and you’re told to go back to “not the latest and greatest so you have to upgrade later” version). This still didn’t work. This one I do hold Xamarin accountable for. Assuming I am using Xamarin Studio AND on a MAC AND not testing the seemingly non-edge-case scenario of developing with Visual Studio on a Windows-based machine is a pretty big let-down when you are getting started. It should have been tested before being released.

End of Week 2

Struggles aside, I finally feel like I am getting my feet under me and understanding how to leverage my knowledge of development to accomplish a valuable product. I have my projects set up similar to the Mountain Weather sample application and I am starting to lay the foundation for my application(s) and feel like I’m able to move forward.

I’m still confident it is the right choice. I am more comfortable using my .NET development skills and familiar techniques. I haven’t had to learn a whole new development stack as I would have with PhoneGap or other alternatives.