8 Comments

showing the running sample app

This post will focus specifically on how to bind collection of data to a view. In another post I already focused on how to use bindings for data entry, be sure to read that one to get more insight into data binding under iOS with MVVM Light. In this post we will display a list of people using the standard UITableView iOS UI control. Via two buttons we will be able to add or remove a person. The people will be randomly generated by a service but first things first. Let’s start by creating the view.

Model

The people are generate with the help of the NameGenerator.cs, which is a class that generates random first- and last names.

// As found on https://digitaltoolfactory.net/blog/2012/04/how-to-make-a-random-name-generator-in-c/
public static class NameGenerator
{
    public static Random rnd = new Random();

    public static string GenRandomLastName()
    {
        List<string> lst = new List<string>();
        string str = string.Empty;
        lst.Add("Smith");
        // ...

        str = lst.OrderBy(xx => rnd.Next()).First();
        return str;
    }
    public static string GenRandomFirstName()
    {
        List<string> lst = new List<string>();
        string str = string.Empty;
        // male
        lst.Add("Aiden");
        // ...

        //female

        lst.Add("Sophia");
        // ...

        str = lst.OrderBy(xx => rnd.Next()).First();
        return str;
    }
}

This class will be accessed form the view models, but let’s first setup the view.

View

The view consists of a UITableView and two UIButtons which we add in the Storyboard and name them PeopleTableView, AddPersonButtonand  RemovePersonButton.

showing designer when creating the iOS view

After setting up the view next thing on the list is creating the view model.

View Model

In the view model we implement an ObservableCollection to hold the list of people and two RelayCommands which when invoked add and remove a person from the list:

public class MainViewModel : ViewModelBase
{
    public MainViewModel()
    {
        AddPersonCommand = new RelayCommand(AddPerson);
        RemovePersonCommand = new RelayCommand(RemovePerson);
    }

    public RelayCommand AddPersonCommand { get; set; }
    public RelayCommand RemovePersonCommand { get; set; }
    public ObservableCollection<Person> People { get; private set; }

    public async Task InitAsync()
    {
        if (People != null) return;

        People = new ObservableCollection<Person>();
        var people = await InitPeopleList();
        foreach (var person in people)
        {
            People.Add(person);
        }
    }
}

The list data is initialized asynchronously in an initialisation method. Now what is left to do is connect the view model with the view via bindings.

Configuring Bindings

The bindings are setup in the RootViewController.cs, which is attached to the View which we are about to populate and interact with. The command bindings are implemented in the ViewDidLoad method:

public override async void ViewDidLoad()
{
    base.ViewDidLoad();

    await Vm.InitAsync();

    // Setup bindings
    AddPersonButton.SetCommand("TouchUpInside", Vm.AddPersonCommand);
    RemovePersonButton.SetCommand("TouchUpInside", Vm.RemovePersonCommand);
}

The UITableView’s source is set in the ViewWillAppear method - if done in the ViewDidLoad method you will be initially showed nothing until you start scrolling the blank list.

public override void ViewWillAppear(bool animated)
{
    base.ViewWillAppear(animated);

    _tableViewController = Vm.People.GetController(CreatePersonCell, BindCellDelegate);
    _tableViewController.TableView = PeopleTableView;
}

In the CreatePersonCell method the cell we will display gets created.:

private UITableViewCell CreatePersonCell(NSString cellIdentifier)
{
    return new UITableViewCell(UITableViewCellStyle.Default, "Gnabber");
}

In case you are wondering: “But what about cell recycling?”. Well there is some good news, MVVM Light takes care of that for you. That being said currently (version 5.1.1) does not support multiple cell templates for one collection.

The BindCellDelegate sets the content of the cell:

private void BindCellDelegate(UITableViewCell cell, Person person, NSIndexPath path)
{
    cell.TextLabel.Text = person.FullName;
}

When all is setup we can start up the app you will be able to add and remove people to the list without having to react any further to the events or updating the table source any further.

Conclusion

In this post you saw how you can bind a list of data to an iOS UITableView. Further demonstration showed how easy it is to change the content of the list and updating the UI with the new data. MVVM Light not only allows to integrate your view models nicely in under iOS but only provides some nice little helpers when it comes down to creating an iOS TableSource.

Thanks again to Laurent Bugnion providing us with this great library.

You can find the whole sample on GitHub.

0 Comments

title_thumb2

On the 6. October 2015 Microsoft introduced it’s new devices all destined to run Windows 10.

The first Device was the HoloLenswhich was demoed with a immersive game experience showing how HoloLens can integrate the furniture of your living room in the game. Plus the HoloLens should start to be available next year for developers for 3000$, so far only US availability has been announced, but my hopes are still high that it will reach Europe and other countries outside of the US soon after that.

band2_thumb

After the HoloLens the new Microsoft Band 2 was introduced. The specs of the band leaked before the event and they seem to be have quite spot on. The new band has a curved display, looks sleeker and has an additional 11th sensor (a barometer) which allows it to track elevation/steps. The band is focused on sport and tracking the users physical activities. The data is stored in the Microsoft health service which allows the user to analyse all of his activities i.e. golf, sleep, running and many more. The Data is stored as usually done with these services in the cloud and not on the devices of the user.

Further Microsoft partnered up with quite a few companies to ensure the band will have apps that provide the user with additional apps and notifications right at your wrist.

Windows Mobile

Lumia-950_thumb2

With the Lumia 950 and 950 XL Microsoft finally has introduced two flagship phones which has been overdue and long awaited. Since the Lumia Icon/930 and Lumia 1520 which they are replacing have been on the market for years(!). The new Lumias keep true to their heritage of providing great Cameras (20MP incl. image stabilization), great displays and the obligate bump in battery size. Further the following specs stick out:

  • Expandable storage via SD-Card
  • 3 GB RAM
  • Snapdragon 808 processors
    • 6-Cores
    • 8-Cores XL
  • USB-C connector

The new USB-C connector allows an ease of use and greater bandwidth but there is more, with the new phones Microsoft introduces Continuum. With an additional accessory called a Microsoft Display Dock you can plug in your phone to a monitor, keyboard and mouse allowing you to control desktop applications such as Word, PowerPoint etc.. The apps that can be used will be based on the Universal Windows Platform (UWP) which allows developers to adopt for different screen sizes. So when the app provides resolutions for phone and desktop factors the same phone app will be displayed differently and allow the user to harness the full power of a desktop setup such as using a mouse and a real keyboard.

While connected to the Microsoft Display Dock the phone will still be available as a phone, meaning you can make calls, write and receive texts etc.. So it isn’t just simply projecting the screen of the phone to another display but it actually will bring up a (limited) Windows 10 desktop experience which I see some very interesting scenarios arising and allows you to use the phone as a PC! Smile

While the Lumia 950 und Lumia 950 XL are high end phones Microsoft also introduced the new Lumia 550 which will provide a cheaper alternative without the Continuum though but still providing quite some bang for the buck.

Surface Pro 4

sp4_thumb4

The Surface Pro 4 is the expected update of the Surface Pro 3. While keeping the dimensions of the SP3 the SP4 comes with the latest Intel chipset, up to 16 GB RAM and 1 TB hard drive. These specs are a great bump and will allow to run Virtual Machines easily from your SP4. Keeping the dimensions will mean that all the external hardware accessories for the SP3 will work with a SP4 and vice versa. If you are the proud owner of a SP3 and have a dock. You will be able to simple reuse the dock for the SP4. All the hardware released for the SP4 also works for the SP3.

While keeping the overall dimensions the SP4 comes with a greater resolution which comes to the cost of the bezel. The screen now comes at 12.3 inches and sports 2736 x 1824 resolution which results in a really high res display at 267 pixels per inch (ppi).

Type cover

The new type cover comes with a full keyboard layout, 40% larger track pad and there will even be versions with a biometric finger reader. Real world testing will prove how much better it is overall but a full size keyboard layout surely sounds lovely.

Pen

The pen has been overhauled slightly. The backend tip now not only is the OneNote button but also serves again as rubber as it was the case with the SP1 & 2 pens. The pen tip can be interchanged which will allow artistic and design folks to choose individual brushes simply by changing the tip and sport the physical feel.

pen_thumb1

Another great plus is that the pen now attaches magnetically to the Surface, so no more after thought latches needed. I really like this additional feat as I never grew warm to the latch (in my case still in the original packaging…).

Docking Station

surface_dock_thumb3

The new docking station no longer requires you to place the Surface Pro into it. It is an elegant little box that you can attach via the power connector. The new Docking Station provides gigabit Ethernet, two display ports, four USB 3.0 ports, audio out and of course power to the Surface Pro 4 and can be used with the Surface Pro 3.

 

(One more thing) Surface Book

The biggest surprise (very positive surprise) is the Surface Book. Other then the SP4 it comes with a Keyboard dock that can be removed at the push of a button. The design looks very sleek and though it does not close fully it resembles pretty much a laptop. In the keyboard half of the Surface Book are additional batteries and a custom made NVidia graphics card. So it has no problems stemming graphically intensive work such as 3D design or games.

surfacebook_thumb2

Being able to remove the tablet results in a light weight and really thin tablet (the USB, Power and display ports are all in the keyboard part). The tablet has the form factor of an A4 paper so it should give you known dimensions and with a pen will allow you to get a great note, drawing, etc. paper.

All accessories from the SP4 are compatible with the Surface Book. But you will not be able to stick it into a SP3 docking station. But it will go nicely with the new SP4 docking station which is less bulky and just as clean.

The take away

Microsoft gave an awesome presentation and highlighted a lot of great features that they usually just seemed to forget to bring forward to the crowd. During the great presentation they highlighted the future with HoloLens, the next step for Windows Phone which will be renamed to Windows Mobile with Windows 10 and the great line up of Surface hardware.

With the new hardware I am sure the surface will continue to grow and expand in a market that is looking how to integrate tablets for the workforce which requires additional input compared to a candy crush app.

The phone hardware finally serves again the users that do want to spend some money for a device and brings some great power user features to the I-want-to-get-stuff-done minded people out there.

I personally can’t wait to get my hands on the new hardware and give it a run especially the phones continuum mode and the new Surface Book are looking very nice and I already fear the impact on my bank account Winking smile

3 Comments

Screenshot_2015-10-02-08-41-47

This is an extension to a previous post that describes how to create bindings for controls. In this post we will look at how to bind a collection to a Android ListView and update the View every time an item is added or removed from the collection in the View Model.

Project Setup

Add the MVVM Light libraries from Laurent Bugnion via NuGet to a Xamarin.Android project:

PM> Install-Package MvvmLight

Then in the View Model create an ObservableCollection which will represent the entire List.

public ObservableCollection<Person> People { get; private set; }

To setup the list we can use an Initializer method, which is currently generated in a separate thread. Now this only makes sense when the list is large i.e. processor heavy which this creation can be if we start jacking up the number. So with the basics all set lets turn our attention to the Activity.

Activity

The ideal place to setup bindings is in the OnCreate method, so by overriding it we can setup the binding for the list. The data container of an Android ListView is the Adapter which we usually have to create by hand. Thanks to MVVM Light we can do this in one line of code:

protected override async void OnCreate(Bundle bundle)
{
    base.OnCreate(bundle);

    SetContentView(Resource.Layout.Main);

    await Vm.InitAsync();
    PeopleListView.Adapter = Vm.People.GetAdapter(GetPersonView);
    // ...
}

The GetPersonView parameter is a method that gets invoked when a displayed row is created. In this method the data of the row is filled accordingly into the UI fields:

private View GetPersonView(int position, Person person, View convertView)
{
    View view = convertView ?? LayoutInflater.Inflate(Resource.Layout.RowPerson, null);

    var firstName = view.FindViewById<TextView>(Resource.Id.FirstName);
    var lastName = view.FindViewById<TextView>(Resource.Id.LastName);

    firstName.Text = person.FirstName;
    lastName.Text = person.LastName;

    return view;
}

Note that the YYY parameter might contain a row that can be reused. As only a certain amount of rows can be displayed at a time rows become obsolete after the user has scrolled them to far out of view. These rows are then passed in as the parameter YYY which is then not null and the fields can be updated with new data. Resulting in a smaller memory footprint which is always good on memory constrained mobile devices.

View

The layouts are simple. For the Activity a simple LinearLayout is used with a ListView within it:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent">
    <ListView
        android:minWidth="25px"
        android:minHeight="25px"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/People" />
</LinearLayout>

The row contains two TextFields that are used to display the persons first and last name.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:padding="5dp">
    <TextView
        android:text="Michael"
        android:textAppearance="?android:attr/textAppearanceMedium"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/FirstName"
        android:layout_margin="5dp" />
    <TextView
        android:text="Westen"
        android:textAppearance="?android:attr/textAppearanceMedium"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/LastName"
        android:layout_margin="5dp" />
</LinearLayout>

The row layout is then inflated in the GetPersonView method.

Adding and removing people from the ListView

Adding and removing people from the collection is now really simple. So all we need to extend our view by are two buttons:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent">
    <LinearLayout
        android:orientation="horizontal"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content">
        <Button
            android:id="@+id/AddButton"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/AddPerson" />
        <Button
            android:id="@+id/RemoveButton"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/RemovePerson" />
    </LinearLayout>
    <!-- ... -->
</LinearLayout>

Then wiring them up in the Activity to Commands in the View Model.

protected override async void OnCreate(Bundle bundle)
{
    // ...

    AddPersonButton.SetCommand("Click", Vm.AddPersonCommand);
    RemovePersonButton.SetCommand("Click", Vm.RemovePersonCommand);
}

In the View Model we simply have two Relay Commands which are initialized in the Constructor:

public MainViewModel()
{
    AddPersonCommand = new RelayCommand(AddPerson);
    RemovePersonCommand = new RelayCommand(RemovePerson);
}

public RelayCommand AddPersonCommand { get; set; }
public RelayCommand RemovePersonCommand { get; set; }

When invoking the commands a person is added or removed from the observable collection which will automatically will be propagated to the presentation in the ListView.

Be aware of the Activity Lifecycle

Note there is a possibility of a memory leak when it comes to the adapter provided by MVVM Light, this has to do with an internal setup of how the Adapter is created. When the Activity is destroyed and recreated e.g. when you turn the device and change the orientation. Internally the activity will be hooked to an event of the observable collection in the View Model. This connection will last even after a new activity is created. Therefore the old activity still hangs around as it is always hooked to the Observable collection in the View Model. This is why in the View Model on every InitAsync the Observable Collection will be replaced with a new instance. This will clean up the trail and allow the no longer used Activity to be garbage collected.

public async Task InitAsync()
{
    if (People != null)
    {
        // Prevent memory leak in Android
        var peopleCopy = People.ToList();
        People = new ObservableCollection<Person>(peopleCopy);
        return;
    }

    People = new ObservableCollection<Person>();

    var people = await InitPeopleList();
    People.Clear();
    foreach (var person in people)
    {
        People.Add(person);
    }
}

Conclusion

In this post we saw how we can bind a collection to a ListView and how updates to the collection are automatically propagated to the view. Further we saw how to handle the lifecycle of an Activity properly without generating a memory leak. Thanks to MVVM Light the complexity displaying collections in an Android app are greatly reduced.

 

The entire sample can be found under GitHub.

This post was previously posted on the Noser Engineering Blog.

0 Comments

TitleImage

Writing Unit, Component and Integration tests allows to test functionality of software modules. In other words letting developers sleep tightly without worries at night. These tests run against certain parts of the code verifying the logic and interaction between modules of the app. All this is usually performed on the developers machine powered by a beefy processor and often unheard amount of RAM when it comes to mobile devices. Wouldn’t it be great if we could get a bit closer to the real thing? Well we can…

In this blog post we will look at how we can run xUnit.net tests on a device. The app will be a Xamarin(.Forms) app, which consists of three platform projects and a shared Portable Class Library which can be used to write logic that can be consumed on every platform.

Setting up xUnit.net

The typical xUnit.net tests are created in a standard .Net library. All that is required is the xUnit.net NuGet package:

PM> Install-Package xunit -Version 2.0.0

Now we can create start writing unit tests, for this blog post let’s stick to the basic calculator example in the BasicMathServiceTest.cs:

public class BasicMathServiceTest
{
    private BasicMathService _basicMathService;

    public BasicMathServiceTest()
    {
        _basicMathService = new BasicMathService();
    }

    [Fact]
    public void Add_GivenTwoNumbers_TheSumIsReturned()
    {
        var x = 35;
        var y = 7;
        var expectedResult = 42;

        var result = _basicMathService.Add(x, y);

        Assert.Equal(expectedResult, result);
    }

    [Fact]
    public void Subtract_GivenTwoNumbers_TheSubtractedResultIsReturned()
    {
        var x = 456;
        var y = 123;
        var expectedResult = 333;

        var result = _basicMathService.Subtract(x, y);

        Assert.Equal(expectedResult, result);
    }

    [Fact]
    public void Mulitply_GivenTwoNumbers_TheResultIsReturned()
    {
        var x = 2;
        var y = 2;
        var expectedResult = 4;

        var result = _basicMathService.Multiply(x, y);

        Assert.Equal(expectedResult, result);
    }

    [Fact]
    public void Divide_GivenTwoNumbers_TheSumIsReturned()
    {
        var x = 848;
        var y = 8;
        var expectedResult = 106;

        var result = _basicMathService.Divide(x, y);

        Assert.Equal(expectedResult, result);
    }

    [Fact]
    public void TheFailingTest()
    {
        var x = 4;
        var y = 2;
        var expectedResult = 8;

        var result = _basicMathService.Add(x, y);

        Assert.Equal(expectedResult, result);
    }
}

The code that we test against lives in a PCL and performs the calculations. Now let’s take these existing tests and execute them on the simulator or even a real device.

Running Tests on devices

For this first add the platforms on which the project will run. Now add the following xUnit.net NuGet package:

PM> Install-Package xunit.runner.devices -Version 1.0.0

Written by Oren Novotny whom we have to thank for enabling xUnit.net on Android, iOS and Windows Phone! This package will automatically add the xUnit.net and other dependencies required for running tests on your devices according to the platform to which it’s being added. Depending on the platform the xUnit.net for Devices package adds different template files as text files:

  • Android
    • MainActivity.cs.txt
  • iOS
    • AppDelegate.cs.txt
  • Windows Phone
    • MainPage.xaml.txt
    • MainPage.xaml.cs.txt

Simply replace the content of their default counterparts e.g. for iOS replace the AppDelegate.cs with the content of the App.Delegate.cs.txt (and thanks to some extra effort by Oren Novotny even the namespaces will just simply match Smile). Now you could simply start adding new class files and write out tests. The runner will automatically find them via reflection (even if you place them in subfolders).

Using existing tests

What is probably a more useful approach is to simply reuse existing tests. This is why in a next step lets see how we can add the unit test file BasicMathServiceTest.cs without creating a duplicate dopy. Simply right click on the Project then Add/Existing Item… browse to the unit test file and add it as link.

Shows the dropdown on the Add button that can be used to add a file as a link.

As a link to the file is simply a pointer to the original we only have to maintain one unit test file and all the links will automatically “update” as they simply reference the original.

Now the Project can be set as startup project and executed on the device. Bellow you see some sample screenshots from an iOS Emulator.

TestOverview

You can even dig into the error messages and see what went wrong during a test.

TestDetails

Conclusion

In this post we saw how to create and reuse xUnit.net tests on devices for iOS, Android and Windows. This can be very powerful when we have to test certain features on a device for example does this work with AOT on iOS? Or simply running integration tests on a real device, giving valuable insights and further allowing to tests performance, latency and so on.

This post focuses on xUnit.net and also shows one of it’s many strengths on the capabilities that can be easily added. The same can be done with NUnit which may be your testing framework of choice and which Xamarin provides project templates to run the tests on a device.

You can find the sample code on GitHub.

1 Comments

For my recent blog post about how to consume a web service in the Portable Class Library (PCL) I decided to write the client for Windows 10 which allows to create apps for every platform that runs Windows 10. In this post I will focus on the platforms Desktop, Tablet and Mobile showing how to create a basic application based on a MVVM architecture. To create a Windows 10 app you will need a computer running Windows 10 and Visual Studio 2015.

Creating a basic app

First lets create a list of people that we can navigate to in the detail view. Here fore we will create two pages. On the first page MainPage.xaml we will simply show the list:

<Page
    x:Class="HttpClientSample.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:HttpClientSample"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    DataContext="{Binding Main, Source={StaticResource Locator}}"
    mc:Ignorable="d">

    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <GridView ItemsSource="{Binding People}" SelectedItem="{Binding SelectedPerson, Mode=TwoWay}"></GridView>

        <AppBar VerticalAlignment="Bottom" IsOpen="True" >
            <AppBarButton Icon="Add" Label="Add Person" Command="{Binding AddNewPerson}" />
        </AppBar>
    </Grid>
</Page>

The user can select an element of the list on which we will navigate to the detail of the person allowing us to edit the person. This is done in the MainViewModel.cs which is based on the MVVM Light Framework for implementation:

public class MainViewModel:ViewModelBase
{
    private readonly IPersonService _personService;
    private ObservableCollection<Person> _people;
    private Person _selectedPerson;

    public MainViewModel(IPersonService personService)
    {
        if (personService == null) throw new ArgumentNullException(nameof(personService));
        _personService = personService;
        _people = new ObservableCollection<Person>();
        ShowPerson = person => { };
        AddNewPerson = new RelayCommand(() => ShowPerson(-1));
    }

    public ObservableCollection<Person> People => _people;
    public Action<int> ShowPerson { get; set; }

    public Person SelectedPerson
    {
        get { return _selectedPerson; }
        set
        {
            if (_selectedPerson == value) return;
            _selectedPerson = value;
            RaisePropertyChanged(nameof(SelectedPerson));
            if (_selectedPerson != null) ShowPerson(_people.IndexOf(_selectedPerson));
        }
    }

    public ICommand AddNewPerson { get; private set; }

    public async Task Init()
    {
        var people = await _personService.GetPeople();

        _people.Clear();

        foreach (var person in people)
        {
            _people.Add(person);
        }
    }
}

The View Model also prepares the List of people that is displayed on the main page. The PersonDetailPage.xaml will allow to edit the first and surname of the person:

<Page
    x:Class="HttpClientSample.PersonDetailPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:HttpClientSample"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    DataContext="{Binding Person, Source={StaticResource Locator}}"
    Loaded="PersonDetail_OnLoaded"
    mc:Ignorable="d">

    <StackPanel Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <TextBox Header="Firstname" Text="{Binding Firstname, Mode=TwoWay}"/>
        <TextBox Header="Lastname" Text="{Binding Lastname, Mode=TwoWay}"/>
        <Button Content="Save" Command="{Binding StoreCommand, Mode=TwoWay}" IsEnabled="{Binding HasPendingChanges}" HorizontalAlignment="Center" Margin="0,10"/>
    </StackPanel>
</Page>

When selecting save the person will be updated, all the logic is implemented in the PersonDetailViewModel.cs:

public class PersonDetailViewModel:ViewModelBase
{
    private readonly IPersonService _personService;
    private int _id;
    private string _firstname;
    private string _lastname;
    private bool _hasPendingChanges;

    public PersonDetailViewModel(IPersonService personService)
    {
        if (personService == null) throw new ArgumentNullException(nameof(personService));
        _personService = personService;

        StoreCommand = new RelayCommand(StorePerson, () => true);
        HasPendingChanges = false;
    }

    public bool HasPendingChanges
    {
        get { return _hasPendingChanges; }
        set
        {
            if (value == _hasPendingChanges) return;
            _hasPendingChanges = value;
            RaisePropertyChanged(nameof(HasPendingChanges));
        }
    }

    public string Firstname
    {
        get { return _firstname; }
        set
        {
            if (value == _firstname) return;
            _firstname = value;
            HasPendingChanges = true;
            RaisePropertyChanged(nameof(Firstname));
        }
    }

    public string Lastname
    {
        get { return _lastname; }
        set
        {
            if (_lastname == value) return;
            _lastname = value;
            HasPendingChanges = true;
            RaisePropertyChanged(nameof(Lastname));
        }
    }

    public ICommand StoreCommand { get; set; }

    public async Task Init(int id)
    {
        _id = id;
        var person = id > 0 ? (await _personService.GetPeople()).ToList()[id] : new Person("", "");
        Firstname = person.FirstName;
        Lastname = person.LastName;
        HasPendingChanges = false;
    }

    private async void StorePerson()
    {
        HasPendingChanges = false;

        var person = new Person(Firstname, Lastname);

        if (_id >= 0)
        {
            await _personService.UpdatePerson(_id, person);
        }
        else
        {
            await _personService.CreatePerson(person);
        }
    }
}

To prevent the user from invoking the storing of a person multiple times the store button is only enabled when there are pending changes and you probably want to improve the error handling in production code as it is non-existent in the StorePerson method.

Basic Navigation

From the main page we implement the navigation in MainPage.xaml.cs which allows the user to navigate to the detail page. We also pass along a navigation parameter which contains the ID or ahem in this basic example the array index of the person we want to see:

private void ShowPerson(int personId)
{
    Frame.Navigate(typeof (PersonDetailPage), personId);
    _viewModel.SelectedPerson = null;
}

The navigation is done over Frame.Navigate, which takes the type of the target and a parameter as an argument. The SelectedPerson is then set to null, after invoking the navigation. This is done so that the user may reselect the person the second time around.

Additionally when the user adds a person over the AppBar it will invoke the same navigation method but pass in the –1 as parameter indicating that no Index is set.

Further the user has the possibility to navigate back to the main page. Here fore we have to enable the back navigation which we set in the Loaded event handler of the person detail page and add an event handler for the BackRequest:

private void PersonDetail_OnLoaded(object sender, RoutedEventArgs e)
{
    SystemNavigationManager.GetForCurrentView().AppViewBackButtonVisibility = AppViewBackButtonVisibility.Visible;
    SystemNavigationManager.GetForCurrentView().BackRequested += OnBackRequested;
}

The event handler is implemented as follows:

private void OnBackRequested(object sender, BackRequestedEventArgs backRequestedEventArgs)
{
    if (Frame.CanGoBack)
    {
        Frame.GoBack();
        backRequestedEventArgs.Handled = true;
    }
}

While testing the app under Windows 10 mobile I noticed that the navigation was invoked twice when selecting the hardware back button. By setting the Handled property to true in the event arguments the framework is indicated that the navigation has been taken care of.

Taking it to other form factors

A great thing about creating your apps as a Universal Windows Platform app is that the APIs remain the same across the devices. In regards to the upcoming Windows 10 Mobile release we can even reuse the UI code. So we can run this basic app on a phone without making any changes. The UI will be automatically adopted to the new form factor.

Now of course for more complex apps you will want to use different layouts according to the screen size, but even then you will be creating adaptive layouts (same as with responsive Websites) rather than developing multiple apps to target different platforms. So a lot less overhead and work to have a running app across multiple form factors.

Conclusion

In this post we saw how to create a basic Windows 10 UWP app including basic navigation features and how to implement the MVVM pattern. If you are coming from a WPF, Silverlight, Windows 8.x or Windows Phone background you have seen that a lot of elements are very familiar.

I’ve been lately playing around with F# which unfortunately is currently not a supported language to write UWP apps. This also includes not being able to share Portable Class Libraries with UWP apps. If you feel the same way as me or want to throw the F# community a bone please let Microsoft know that they enable support for F# UWP apps here.

You can find the entire sample code of this blog post on GitHub.