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…

 

One thought on “Xamarin Forms Navigation: Part 2 – MVVM and the TabbedPage

  1. […] Part 2, I created a pattern where I could use the MVVM pattern to manage the navigation on a TabbedPage. […]

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s