Nick's .NET Travels

Continually looking for the yellow brick road so I can catch me a wizard....

Android Emulator Exception after updating to Visual Studio 15.9 preview 3

I noticed earlier this evening that there was an update available for Visual Studio 15.9. Normally I wait a few days to update as I’m not in any particular hurry but I noticed in the blog post and release notes that work had been done on the Android build and execution. I also remembered that I hadn’t updated Visual Studio or my emulator images since updating my Surface Book 2 to the latest Windows update – it contains a fix for the awful performance of the Android emulator running on Windows hypervisor. Anyhow, the upshot is that I updated Visual Studio to the latest preview….

I decided to drop my existing emulator images and create new ones. Unfortunately this was a bad idea as I was then unable to start the new emulator images. When I attempted to start the emulator I would get an error stating “The requested operation requires elevation. (Exception from HRESULT: 0x800702E4)".

image

Turns out I’m not the only person seeing this, as someone had already reported this issue.

It also turns out that there’s a simple solution…. close the Android Device Manager and just hit Run from within Visual Studio. Turns out that this causes the emulator image to boot, deploy and run the application. And all the updates seem to do the trick, debugging is back to an acceptable speed.

Intercepting the Android Software Back Button in Xamarin.Forms

Recently an issue was raised on MvvmCross that claimed there was an issue intercepting the back button in a Xamarin.Forms + MvvmCross application running on Android. I spent a bit of time investigating the issue as I didn’t believe MvvmCross was doing anything that would prevent an application from intercepting the back button. In this post I’ll walk through my investigation and demonstrate a solution that I came up with. Just for clarity, the issue was referring to intercepting the software back button that appears in the navigation bar.

In the comments someone had referenced a solution proposed by Udara Alwis (https://theconfuzedsourcecode.wordpress.com/2017/03/12/lets-override-navigation-bar-back-button-click-in-xamarin-forms/) which states that the OnOptionsItemSelected method can be overridden in the Activity that hosts the Xamarin.Forms application. Further comments indicated that this solution didn’t work for a Xamarin.Forms application that was using MvvmCross. My starting point was to of course validate this assertion. Using the Playground sample in the MvvmCross source code I attempted to override the OnOptionsItemSelected method in the MainActivity of the Android application. I ran the application and sure enough, the OnOptionsItemSelected method does not get invoked when tapping the software back button.

Having validated that the MvvmCross Playground was indeed broken, I next wanted to test to see if it was an issue with Xamarin.Forms itself. To do this, I started by creating a new Xamarin.Forms application (I’m just going to build for Android, since this is just a sample).

image

The Blank application template comes with a single page, MainPage. I added a second page to the application:

image

Onto the MainPage I added a Button and in the Clicked event handler added code to navigate to the page I just added:

private async void Button_Clicked(object sender, EventArgs e)
{
     await Navigation.PushAsync(new Page1());
}

In order to get the navigation bar to appear, I changed the App constructor to make use of a NavigationPage:

public App()
{
     InitializeComponent();

    MainPage = new NavigationPage(new MainPage());
}

Lastly, I needed to add the OnOptionsItemSelected override to the MainActivity.

public override bool OnOptionsItemSelected(IMenuItem item)
{
     return base.OnOptionsItemSelected(item);
}

Unfortunately, after doing all this, the OnOptionsItemSelected method was still not called. Looks like the issue sits with Xamarin.Forms, so it’s time to start trawling through the source code.

After an initial inspection it appears that the FormsAppCompatActivity does override the OnOptionsItemSelected method, but that doesn’t explain why overriding it in my application wouldn’t work. However, further inspection revealed that the NavigationPageRenderer (the renderer for the NavigationPage) implements the IOnClickListener interface and registers itself with the ActionBar (which corresponds to the navigation bar). Doing this prevents the call to the OnOptionsItemSelected method, which is why we were not seeing it called.

I figured that I would try extending the default renderer and provide my own implementation of the IOnClickListener interface:

[assembly: ExportRenderer(typeof(NavigationPage), typeof(HackBackButton.CustomNavigationPageRenderer))]
namespace HackBackButton
{
     public class CustomNavigationPageRenderer : NavigationPageRenderer, IOnClickListener
     {
         public CustomNavigationPageRenderer()
         {
         }

        public CustomNavigationPageRenderer(Context context) : base(context)
         {
         }

        public new void OnClick(Android.Views.View v)
         {
             Element?.PopAsync();
         }
    }
}

This works and the OnClick method is invoked when the software back button is tapped. Of course, we then need to route this to the current page so that it can decide if it should allow the back navigation.

Turns out that it’s nothing to do with MvvmCross and that the issue lie entirely with Xamarin.Forms. There needs to be a better way to intercept the back navigation. Someone has already listed a issue with Xamarin.Forms, so add a comment and make sure this issue gets some attention.

Getting Started with Xamarin.Forms and Device Customization using OnIdiom

Previous posts in this sequence on Getting Started with Xamarin.Forms:
Multi-Targeting in Visual Studio, SDK Versions, MvvmCross, Authenticating with ADAL
Refactoring MvvmCross and Services, Effects, Navigation with MvvmCross
Presentation Attributes in MvvmCross, Resources and Styles, Resource Dictionaries
Platform Specific Resources with OnPlatform

Last post I covered how to use OnPlatform to tailor resources and styles based on the target platform. However, there is an alternative dimension you can tailor the layout of your application and that’s using OnIdiom. If you look at the definition of the OnIdiom class you can see that it allows you to define different values for Phone, Tablet, Desktop, TV and Watch.

image

To use this in XAML is very similar to using OnPlatform:

<Label>
     <Label.Text>
         <OnIdiom x:TypeArguments="x:String">
             <OnIdiom.Phone>Hello from a phone app</OnIdiom.Phone>
             <OnIdiom.Desktop>Hello from a desktop app</OnIdiom.Desktop>
         </OnIdiom>
     </Label.Text>
</Label>

As you can see from the code snippet this provides different string values for when the application is run on a phone vs being run on a desktop.

Note: Tablet only works well for iOS and Android. Xamarin.Forms running on UWP currently doesn’t distinguish between Windows running in desktop or tablet mode, and as such will always use the Desktop idiom values.

Getting Started with Xamarin.Forms, Refactoring MvvmCross and Services

Previous posts in this sequence:
Getting Started with Xamarin.Forms and Multi-Targeting in Visual Studio
Getting Started with Xamarin.Forms and SDK Versions
Getting Started with Xamarin.Forms with MvvmCross
Getting Started with Xamarin.Forms and Authenticating with ADAL

In this post I’m going to do a bit of a refactor based on the work completed in the previous post where we added code directly into the MainViewModel to use the Azure Active Directory Authentication Library. This would be fine if the MainViewModel was the only view model in the application that needed access to the Authenticate method. As I will probably want to make use of it elsewhere, I’ve decided to refactor that code into a class called CredentialService.

When I wired up MvvmCross a couple of posts ago, I did so without going into much detail on how the relationship between view models and their corresponding page is setup. I’m not going to delve into the inner workings of MvvmCross but suffice to say that there is some reflection magic that goes on based on the names of the classes. A view model with the name MainViewModel will be paired with a page called MainPage.

In addition to the magic that glues the view model and pages together (and thus the navigation model) MvvmCross also has a quite powerful dependency injection framework. The CredentialService that I’ll be creating will be registered with the DI framework as a singleton that can be easily accessed.

Let’s start by creating the CredentialService and it’s corresponding interface ICredentialService in a folder called Services in the Core library.

public partial class CredentialService:ICredentialService
{
     private const string AuthEndpoint = "
https://login.microsoftonline.com/{0}/oauth2/token";

    private const string ResourceId = "https://graph.windows.net/";
     private const string TenantId = "[your tenantId]";
     private const string ClientId = "[your clientId]";
     private const string RedirectURI = "[your redirectURI]";

    public string AccessToken { get; set; }

    public async Task<string> Authenticate()
     {
         string authority = string.Format(CultureInfo.InvariantCulture, AuthEndpoint, TenantId);
         var authContext = new AuthenticationContext(authority);

        var result = await authContext.AcquireTokenAsync(ResourceId, ClientId, new Uri(RedirectURI), this.PlatformParameters);
         AccessToken = result.AccessToken;
         return AccessToken;
     }
}

public interface ICredentialService
{
     Task<string> Authenticate();
}

The platform specific code will need to be extracted out of the MainViewModel.Platform.cs into the corresponding CredentialService.Platform.cs. For example the UWP class would be:

public partial class CredentialService
{
     private IPlatformParameters PlatformParameters => new PlatformParameters(PromptBehavior.Always, false);
}

In order to register the CredentialService with the DI framework, we just need to add a small bit of code to the Initialize method of the App class in the Core library

public override void Initialize()
{
     CreatableTypes()
         .EndingWith("Service")
         .AsInterfaces()
         .RegisterAsLazySingleton();

    RegisterAppStart<MainViewModel>();
}

The last step is to make use of the service in the MainViewModel. We do this by adding a parameter of type ICredentialService to the MainViewModel constructor.

private ICredentialService CredentialService { get; }
public MainViewModel(ICredentialService credentialService)
{
     CredentialService = credentialService;
}

private async Task Authenticate()
{
     Debug.WriteLine(await CredentialService.Authenticate());
}

And that’s it – we haven’t changed any functionality but the solution is better organised and structured in a way that services can easily be added without cluttering up view models.

image

Where’s the Latest Android Emulator?

I’ve been struggling to get the Android emulator to perform at a level where debugging was possible. After upgrading to VS15.8 I was able to switch over to use the new Windows Hypervisor support (note that “Windows Hypervisor Platform” is different from the Hyper-V feature in the Windows Features dialog). However, I found that the performance of the emulator was so bad that debugging was barely possible – infinitely worse than when I was using the HAXM support.

After spending a bit of time searching online I came across references to versions of the Android emulator that were higher than what I was using. I double-checked the Android SDK Manager just in case there were updates available but there were none.

Eventually I realised that by selecting the cog in the lower right corner of the SDK Manager I was able to switch from the Microsoft repository across to the Google repository.

image

After switching to the Google repository there was indeed an update to the tools, which included the new emulator version.

Did this fix the performance issue? Not entirely. Performance was better in the Android P emulator but still nowhere near as good as a real device (even an old one).

If all else fails, go to the source. I reached out to Miguel and asked if this was a known issue.

image

Looks like we need to wait for a Windows update in order to get this performance fix.

Getting Started with Xamarin.Forms and Authenticating with ADAL

Previous posts in this sequence:
Getting Started with Xamarin.Forms and Multi-Targeting in Visual Studio
Getting Started with Xamarin.Forms and SDK Versions
Getting Started with Xamarin.Forms with MvvmCross

Now that we’ve got the basics of an application, we’re going to add some authentication using the Azure Active Directory Authentication Library. We’re going to start with registering an application with Azure Active Directory (AAD) (the docs do cover this here but I figured I’d cover it again anyway). Start by heading over to the Azure portal and selecting Azure Active Directory from the set of tabs on the left.

image

In the list of tabs for the AAD, find the App Registrations tab

image

Click “New application registration” and fill in the details for the new app

image

Note that the Sign-on URL doesn’t have to be a real URL, just one that both the portal and the app know about – we’ll use this later! After you’re done creating the app registration you should be able to retrieve the Application ID. Save this information for later as we’ll need it when we’re authenticating the user within our application.

image

The pieces of information you’ll need in order to use ADAL within your application are:

clientId – This is the Application ID that was displayed after you created the app registration in the Azure portal. This is a GUID

redirectUri – This is the Redirect URI that you specified when creating the app registration. If you didn’t write this down, or you want to double check, or change it, you can do so by clicking the Redirect URIs tab under Settings for the app registration. This is a URL (e.g. https://stratapark)

resourceId – This is the identifier of the resource you want to access. In this case we just want to authenticate the user, so we’re going to use the default resource, which is the AAD directory itself, https://graph.windows.net/. This can be a URL or a GUID depending on the type of resource you’re referencing

tenantId – This is the identifier of the tenant that you’re authenticating against. This can be the URL or GUID of your tenant.

To retrieve the tenantId you need to select the Properties tab of the Azure Active Directory and copy the Directory ID

imagehttps://www.nuget.org/packages/Microsoft.IdentityModel.Clients.ActiveDirectory/

Now that we’ve setup the app registration, we’re good to start writing some code. Firstly, we need to add a reference to the ADAL library from NuGet – search for Microsoft.IdentityModel.Clients.ActiveDirectory

image

Add the ADAL library to all projects.

Let’s start with the UI and add a button to the MainPage.

<Button Text="Authenticate" Command="{Binding AuthenticateCommand}" />

And of course we need a command within the MainViewModel. In fact we’ll add the bulk of the authentication code to the MainViewModel too:

private IMvxCommand authenticateCommand;
public IMvxCommand AuthenticateCommand => authenticateCommand ?? (authenticateCommand = new MvxAsyncCommand(Authenticate));

private const string AuthEndpoint = "https://login.microsoftonline.com/{0}/oauth2/token";

private const string ResourceId= "https://graph.windows.net/";
private const string TenantId = "[your tenantId]";
private const string ClientId = "[your clientId]";
private const string RedirectURI = "[your redirectUri]”;

public async Task Authenticate()
{
     string authority = string.Format(CultureInfo.InvariantCulture, AuthEndpoint, TenantId);
     var authContext = new AuthenticationContext(authority);

    var result = await authContext.AcquireTokenAsync(ResourceId, ClientId, new Uri(RedirectURI), PlatformParameters);
     Debug.WriteLine( result.AccessToken);
}

The only thing missing is the PlatformParameters (bolded in the code above). As the name suggests, these are platform specific parameters required by the ADAL library. For each platform we need to expose a property that returns an IPlatformParameters within the MainViewModel.Platform.cs for each platform.

Android

private IPlatformParameters PlatformParameters => new PlatformParameters(CurrentActivity, true, PromptBehavior.Auto);
public Activity CurrentActivity
{
     get
     {
         var top = Mvx.IoCProvider.Resolve<IMvxAndroidCurrentTopActivity>();
         return top.Activity;
     }
}

iOS

private IPlatformParameters PlatformParameters => new PlatformParameters(GetTopViewController(),true, PromptBehavior.Auto);
public static UIViewController GetTopViewController()
{
     var window = UIApplication.SharedApplication.KeyWindow;
     var vc = window.RootViewController;
     while (vc.PresentedViewController != null)
         vc = vc.PresentedViewController;

    if (vc is UINavigationController navController)
         vc = navController.ViewControllers.Last();

    return vc;
}

UAP

private IPlatformParameters PlatformParameters => new PlatformParameters(PromptBehavior.Always, false);

NetStandard

private IPlatformParameters PlatformParameters => null;

Note: you need to provide the NetStandard implementation otherwise the NetStandard target won’t build.

There is one more thing we need to add. Android requires an additional piece of code within the Activity that hosts the Xamarin.Forms application

protected override void OnActivityResult(int requestCode, Result resultCode, Intent data)
{
     base.OnActivityResult(requestCode, resultCode, data);
     AuthenticationAgentContinuationHelper.SetAuthenticationAgentContinuationEventArgs(requestCode, resultCode, data);
}

If your Android application authenticates but doesn’t ever return the access token, chances are that your OnActivityResult override is either missing, or on the wrong Activity – I spent a bit of time trying to work out why iOS and UWP worked but Android would just hang; turns out I was missing this override.

There you have it – you’re good to go with using ADAL to authenticate your users within your Xamarin.Forms application

Getting Started with Xamarin.Forms with MvvmCross

Previous posts in this sequence:

Getting Started with Xamarin.Forms and Multi-Targeting in Visual Studio

Getting Started with Xamarin.Forms and SDK Versions

Next up is adding in MvvmCross – no surprises here: Add the MvvmCross package to all projects in the solution

image

We need to make a few adjustments to the Core library. First up, we need to add an App class to Core that inherits from MvxApplication. For the moment the only thing this class is going to do is to set the initial view model of the application. One of the core ideas behind MvvmCross is that navigation is driven from view models, rather than at the view level. By setting the initial view model, we’re effectively defining which view will be shown when our application launches.

public class App : MvxApplication
{
     public override void Initialize()
     {
         RegisterAppStart<MainViewModel>();
     }
}

We’ll do a bit of tidying up whilst we’re making changes to the Core project. We’ll create a ViewModels folder and move MainViewModel into folder

We’ll update MainViewModel and MainViewModel.Platform.cs (all four) to add ViewModels to namespace. We’ll also update MainViewModel to inherit from MvxViewModel.


Now that we’ve updated the Core library, we’ll turn our attention to the UI library and the head projects. We’ll add the MvvmCross.Forms NuGet reference to all projects, except Core.

image

The only other change we need to make to the UI library for the moment is to update MainPage to inherit from MvxContentPage instead of ContentPage. You’ll need to do this in both the xaml and xaml.cs files. However, I would recommend dropping the inheritance from the xaml.cs file as it is not required in multiple places.


Next up we need to adjust each of the head projects (UWP, iOS and Android) so that they use MvvmCross to launch the Xamarin.Forms views.

UWP

Rename MainPage to HostPage (in both MainPage.xaml and MainPage.xaml.cs, and the filenames themselves) in the UWP head project – we do this to avoid any confusion between the name of the page and any views that are automatically associated with MainViewModel. Also update HostPage to inherit from MvxFormsWindowsPage.

For UWP we need an additional step due to some limitation around the support for generics. Add a help class ProxyMvxApplication, defined as follows:

public abstract class ProxyMvxApplication : MvxWindowsApplication<MvxFormsWindowsSetup<Core.App, UI.App>, Core.App, UI.App> { }

Change App.xaml and App.xaml.cs to inherit from ProxyMvxApplication, and remove all code in App.xaml.cs other than the constructor which should contain a single call to InitializeComponent. Override the HostWindowsPageType method in the App class

protected override Type HostWindowsPageType()
{
     return typeof(HostPage);
}

Build and run the UWP application

iOS

Update the AppDelegate as follows

public partial class AppDelegate : MvxFormsApplicationDelegate<MvxFormsIosSetup<Core.App, UI.App>, Core.App, UI.App>
{ }

Build and run the iOS application.

Android

Rename and update the MainActivity as follows. Again, we rename the activity to avoid confusion with any activity or view that would be automatically associated with MainViewModel.

public class HostActivity
         : MvxFormsAppCompatActivity<MvxFormsAndroidSetup<Core.App, UI.App>, Core.App, UI.App>
{ }

Build and run the Android application.

You may experience a build error when you attempt to build and run the Android application, relating to referencing the Mono.Android.Export library. In this case, use the Add Reference dialog to manually add the missing reference.

image


There you have it – all three platforms running Xamarin.Forms application powered by MvvmCross.

Getting Started with Xamarin.Forms and SDK Versions

In my previous post I did a walk through of creating a new Xamarin.Forms application and setting up the Core and UI projects for multi-targeting. Whilst I covered updating the various NuGet packages, I didn’t look at the SDK versions for the three platforms. In this post I’m going to look at the options for setting the SDK version, as it’s important that you update this to target the latest SDK version, even if your application is going to support older platform versions.

Android

If you right-click on the Android head project and select Properties you’ll see the Project Properties pane.

Start by increasing the Target Framework by selecting the highest Android version that you have installed

image

Next, on the Android Manifest tab, select “Use Compile using SDK version” under the Target Android version. On this tab you can also set the Minimum Android version if you don’t want to accept the defaults – this may be relevant if you don’t want a massive support matrix for your application as it will prevent installation on devices running a version of Android older than the minimum.

image

Build and run the Android application to make sure you haven’t broken anything and then commit your changes – in this case the first change would have made changes to the Android csproj file, whereas the second change would have changed the AndroidManifest.xml file.

iOS

Setting the SDK Version for iOS is straight forward and the recommendation is to leave the “Default” (which should be the default value) in the SDK Version dropdown on the iOS Build tab on the Properties pane for the iOS application.

image

If you want to adjust the minimum supported version of iOS, you can do this by double-clicking the Info.plist file for your iOS application and then adjusting the Deployment Target.

image


UWP

Both the Target and Min version of the UWP application can be set from the Application tab of the Project Properties pane. Setting the Target version defines the SDK version that will be used to compile the application and thus the APIs that are available.

image


Core and UI

Now that the Core and UI libraries are set to be multi-targeted it is also necessary to define what the target framework/version should be for each platform. If you don’t do this, you may be limited as to what platform APIs are available. Rather than setting these values in each of the libraries, we can create a file, Directory.build.targets, in the solution folder and include the appropriate elements there – this will get included in all projects that support the new csproj format. In this case the contents of our Directory.build.targets file will look like

<Project>
   <PropertyGroup Condition="$(TargetFramework.StartsWith('netstandard'))">
     <DefineConstants>$(DefineConstants);NETSTANDARD;PORTABLE</DefineConstants>
   </PropertyGroup>
   <PropertyGroup Condition="$(TargetFramework.StartsWith('uap'))">
     <DefineConstants>$(DefineConstants);NETFX_CORE;XAML;WINDOWS;WINDOWS_UWP</DefineConstants>
     <TargetPlatformVersion>10.0.17134.0</TargetPlatformVersion>
     <TargetPlatformMinVersion>10.0.16299.0</TargetPlatformMinVersion>
   </PropertyGroup>
   <PropertyGroup Condition="$(TargetFramework.StartsWith('Xamarin.iOS'))">
     <DefineConstants>$(DefineConstants);MONO;UIKIT;COCOA;IOS</DefineConstants>
   </PropertyGroup>
   <PropertyGroup Condition="$(TargetFramework.StartsWith('MonoAndroid'))">
     <DefineConstants>$(DefineConstants);MONO;ANDROID</DefineConstants>
   </PropertyGroup>
</Project>

The csproj for both Core and UI projects also needs to be updated to replace the target framework MonoAndroid81 with MonoAndroid90.

All your projects should now be targeting the latest framework/sdk versions. If you find that some, or all, of these changes don’t take effect, you may need to either reload specific projects, or restart Visual Studio.

Building a TipCalc using Platform Uno

Recently I’ve been playing around with Platform.Uno – I’ve long held the view that Microsoft’s Xamarin.Forms was a stop-gap in delivering a true cross-platform solution. Whilst Xamarin.Forms is a highly productive platform, it has some severe limitations, specifically around overriding the look and feel of the native controls. This is where Flutter has stolen a lot of mindshare, mainly because customers and companies looking to build apps, no longer look for apps that match the platform style. They’re much more focussed on strong brand presence and great user experience, meaning that a great Material app on iOS will get better reviews and usage than a mediocre app that uses the default iOS style. Platform Uno attempts to deliver on what I believe the Universal Windows Platform (UWP) should have been – taking UWP XAML across iOS, Android and Web Assembly.

Anyhow, here goes with building a TipCalc. I’ll start with the basic UWP application:

I’ll create a separate project for our ViewModel:

Running the UWP app at this point gives an operational tip calculator

image

So now, let’s add some Uno goodness. We���ll start by moving the MainPage.xaml into its own class library:

  • Add a new project based on the Class Library (.NET Standard) project template, TipCalc.UI
  • Remove class1.cs
  • Add reference to project TipCalc.Core
  • Move MainPage.xaml and MainPage.xaml.cs to the TipCalc.UI project
  • Change namespace from TipCalc.UWP to TipCalc.UI for both MainPage.xaml and MainPage.xaml.cs
  • Edit TipCalc.UI.csproj to allow it to multi-target (ie generate multiple dlls that target UWP, Droid, iOS etc) and make sure correct build action is set for MainPage.xaml
  • Add reference to Uno.UI nuget package (currently in prerelease).
  • Final TipCalc.UI.csproj should look similar to

  • <Project Sdk="MSBuild.Sdk.Extras/1.5.4">
       <PropertyGroup>
         <TargetFrameworks>xamarinios10;MonoAndroid80;uap10.0</TargetFrameworks>
       </PropertyGroup>

      <PropertyGroup Condition=" '$(TargetFramework)' == 'uap10.0' ">
         <GenerateLibraryLayout>true</GenerateLibraryLayout>
       </PropertyGroup>

      <ItemGroup Condition=" '$(TargetFramework)' == 'uap10.0' ">
         <PackageReference Include="Microsoft.NETCore.UniversalWindowsPlatform" Version="6.1.5" />
       </ItemGroup>

      <ItemGroup>
         <PackageReference Include="Uno.UI" Version="1.31.0-dev.52" />
       </ItemGroup>

      <ItemGroup>
         <Page Include="MainPage.xaml">
           <SubType>Designer</SubType>
           <Generator>MSBuild:Compile</Generator>
         </Page>
       </ItemGroup>

      <ItemGroup>
         <ProjectReference Include="..\TipCalc.Core\TipCalc.Core.csproj" />
       </ItemGroup>
    </Project>

  • Add Uno.UI nuget reference to TipCalc.Core. Resulting csproj should look similar to

  • <Project Sdk="MSBuild.Sdk.Extras/1.5.4">
       <PropertyGroup>
         <TargetFrameworks>xamarinios10;MonoAndroid80;uap10.0</TargetFrameworks>
       </PropertyGroup>

      <ItemGroup>
         <PackageReference Include="Uno.UI" Version="1.31.0-dev.52" />
       </ItemGroup>
    </Project>

  • Add reference to TipCalc.UI to TipCalc.UWP

By all accounts at this point you’ve done a fair bit of lifting with out much to show for it. In fact, because of some absolute genius coding by Microsoft, if you run the UWP application at this point you’ll most likely see a System.AccessViolationException when attempting to navigate to MainPage

image

This seems to be an issue where you’re attempting to navigate to a page that’s defined in a separate assembly and there are no other XAML pages defined in the head (ie UWP) project. Simple solution is just to add a dummy page to the UWP project that you’ll never use…. but seriously Microsoft??? Oh, and this isn’t the first time this has been pointed out (see https://social.msdn.microsoft.com/Forums/windowsserver/en-US/4efa91ad-fa8f-45f0-9864-c2fd2b24477c/uwpc-accessviolationexception-when-navigating-froma-another-assembly?forum=wpdevelop which links to an old post http://danielvaughan.org/posts/uwp/2015/08/15/UWP-AccessViolationException-when-Navigating-to-a-Page-in-Another-Assembly/)

Right, so the question is – after all this effort, how are we any closer to having a cross platform application. Well, let’s spit out the Android build:

  • Add a new project based on the Android App (Xamarin) project template, TipCalc.Droid
    image
  • Use the Blank App template
  • Uninstall any of the Xamarin.Android.Support nuget packages that are installed by default
  • Add reference to Uno.UI nuget package
  • Add reference to both TipCalc.UI and TipCalc.Core
  • Add a reference to Mono.Android.Export
    image
  • Add App.xaml and App.xaml.cs from the TipCalc.UWP project to the TipCalc.Droid project As Link
    image
  • Alter MainActivity to the following

  • [Activity(
         MainLauncher = true,
         ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.ScreenSize,
         WindowSoftInputMode = SoftInput.AdjustNothing | SoftInput.StateHidden
    )]
    public class MainActivity : Windows.UI.Xaml.ApplicationActivity
    {
    }

  • Add an Application class as follows

  • [global::Android.App.ApplicationAttribute(
         Label = "@string/app_name",
         LargeHeap = true,
         HardwareAccelerated = true,
         Theme = "@style/AppTheme"
    )]
    public class Application : Windows.UI.Xaml.NativeApplication
    {
         public Application(IntPtr javaReference, JniHandleOwnership transfer)
             : base(new App(), javaReference, transfer)
         {
         }
    }

Now we’re good to go. Set the TipCalc.Droid to be the start up project and off we go. The app looks basically the same as it did on UWP

image

This took quite a bit of effort to get going but now that it’s there, you can imagine that productivity is going to be quite good. Next up I’ll add in the iOS project but I don’t envisage that, nor Web Assembly, being that hard from the samples I’ve seen to date.

Source code available at https://github.com/nickrandolph/UnoSamples

MvvmCross: Initialize method on the first view model

An issue was raised on MvvmCross following the release of v6 where applications were breaking because they have async code in the Initialize method of the first view model. Changes in v6 mean that the first view model is effectively loaded synchronously. This change was made because applications should not do heavy lifting before displaying the first view of their application as there are platform requirements that will cause the application to terminate if it doesn’t display the first view within the appropriate time window. This change means that any code that attempts to jump to a different thread (even something like Task.Delay) will cause the fist view of the application to break.

In some scenarios this doesn’t make sense – for example if you have a splash screen Activity on Android, the first navigation can be done asynchronously because you already have a view being displayed on the screen. Here I’m going to use a simple example to demonstrate how to resolve this issue – you should only use this if you are using a splash screen for the first view of your application.

Let’s start by breaking our application by adding the following to our first view model:

public override async Task Initialize()
{
     await Task.Delay(2000);
     await base.Initialize();
}

If you make this change and attempt to run your application you’ll see a black screen (on Android – and I’m using Android because we typically have a splash Activity such as in my earlier post).

Next we’re going to fix this by overriding the MvxAppStart class to make the first navigation asynchronous:

public class CustomMvxAppStart<TViewModel> : MvxAppStart<TViewModel>
     where TViewModel : IMvxViewModel
{
     public CustomMvxAppStart(IMvxApplication application, IMvxNavigationService navigationService) : base(application, navigationService)
     {
     }

    protected override void NavigateToFirstViewModel(object hint)
     {
         NavigationService.Navigate<TViewModel>();
     }
}

Note that it’s the bold line that we’ve changed from the built in MvxAppStart class where we call NavigationService.Navigate<TViewModel>().GetAwaiter().GetResult(); which forces the navigation to be done synchronously.

We now need to make sure that our CustomMvxAppStart is used. To do this we just need to change a single line in the App.cs to use RegisterCustomAppStart instead of RegisterAppStart

RegisterCustomAppStart<CustomMvxAppStart<FirstViewModel>>();

And we’re done – running the application now will allow the application to load successfully.

MVX=1: TipCalc - a second example - adding IoC and the Xamarin Android Designer (MVX+1 days of MvvmCross)

Following on from the first post in the MVX+1 series, in this post we’ll create a basic Tip Calculator (mirroring the original post from the N+1 series). However, in this case the first section is a more detailed set of instructions on how to get the basics of all three platforms setup with MvvmCross. Going forward we’ll use this as a starting point so that we don’t need to cover over this in each subsequent post.

Source code: https://github.com/nickrandolph/MvxPlus1DaysOfMvvmCross/tree/master/Mvx-01-TipCalc

Getting Started Instructions (Native Apps)

Note: In this case the name of the application is TipCalc but these instructions can be followed to get any new project started by simply replacing TipCalc with the name of your project.

  1. Create a the new solution by creating a new Class Library (.NET Standard) with the project name set to TipCalc.Core and the solution name to just TipCalc.
  2. Add a new project based on the Blank App (Universal Windows) project template called TipCalc.Uwp (make sure that the Minimum and Target versions are set to at least the Fall Creators Update)
  3. Add a new project based on the Android App (Xamarin) project template called TipCalc.Droid (use the Blank app template)
  4. Add a new project based on the iOS App (Xamarin) project template called TipCalc.iOS (use the Blank app template)
  5. Add a reference to MvvmCross NuGet package (v6.0.0 at time of writing to all four projects)
  6. TipCalc.Uwp: Update NuGet package Microsoft.NETCore.UniversalWindowsPlatform to the latest stable version (6.0.8 at time of writing)
  7. TipCalc.Droid: Update the Android version to Use Latest Platform (Project Properties –> Application –> Target Framework)
  8. TipCalc.Droid: Update Xamarin.Android.Support.Design to latest stable version (27.0.2 at time of writing)
  9. TipCalc.Droid: Add a reference to MvvmCross.Droid.Support.V7.AppCompat package
  10. TipCalc.iOS: Unload project; delete packages.config; edit TipCalc.iOS.csproj and add the following ItemGroup
    <ItemGroup>
       <PackageReference Include="MvvmCross" Version="6.0.0" />
    </ItemGroup>
  11. Add a reference to TipCalc.Core to each of the three head projects (ie TipCalc.Uwp, TipCalc.Droid and TipCalc.iOS)
  12. TipCalc.Core: Rename the default Class1.cs to App.cs, and allow Visual Studio to rename class to App
  13. TipCalc.Core: Change the App class to inherit from MvxApplication
  14. TipCalc.Core: Add a folder, ViewModels, and add a class called FirstViewModel.
  15. TipCalc.Core: Change FirstViewModel to inherit from MvxViewModel
  16. TipCalc.Core: Override Initialize method in App to register services and set startup view model to FirstViewModel
    public override void Initialize()
    {
         CreatableTypes()
                 .EndingWith("Service")
                 .AsInterfaces()
                 .RegisterAsLazySingleton();
         RegisterAppStart<FirstViewModel>();
    }
  17. TipCalc.Uwp: Add a help class ProxyMvxApplication
    public abstract class ProxyMvxApplication: MvxApplication<MvxWindowsSetup<Core.App>, Core.App> { }
  18. TipCalc.Uwp: Change App.xaml and App.xaml.cs to inherit from ProxyMvxApplication
  19. TipCalc.Uwp: Remove all code in App.xaml.cs other than the constructor which should contain a single call to InitializeComponent
  20. TipCalc.Uwp: Delete MainPage.xaml and MainPage.xaml.cs
  21. TipCalc.Uwp: Add a Views folder, and  add a FirstView based on the Blank Page template
  22. TipCalc.Uwp: Change FirstView.xaml and FirstView.xaml.cs to inherit from MvxWindowsPage
  23. TipCalc.Droid: Add a new class, MainApplication, that inherits from MvxAppCompatApplication
  24. [Application]
    public class MainApplication : MvxAppCompatApplication<MvxAppCompatSetup<App>, App>
    {
         public MainApplication(IntPtr javaReference, JniHandleOwnership transfer) : base(javaReference, transfer)
         {
         }
    }

  25. TipCalc.Droid: Rename MainActivity.cs to SplashScreen.cs and let Visual Studio rename the class
  26. TipCalc.Droid: Rename activity_main.axml to SplashScreen.axml, and adjust layout to indicate application loading
  27. TipCalc.Droid: Adjust SplashScreen class to inherit from MvxSplashScreenAppCompatActivity and set NoHistory to true (since we don’t want the user to be able to press the back button and go back to the splash screen)

    [Activity(Label = "@string/app_name", Theme = "@style/AppTheme", MainLauncher = true, NoHistory = true)]
    public class SplashScreen : MvxSplashScreenAppCompatActivity

  28. TipCalc.Droid: Add a folder, Views, and add a new Activity, FirstView.c
  29. [Activity(Label = "FirstView")]
    public class FirstView : MvxAppCompatActivity<FirstViewModel>
    {
         protected override void OnCreate(Bundle bundle)
         {
             base.OnCreate(bundle);

            SetContentView(Resource.Layout.FirstView);
         }
    }

  30. TipCalc.Droid: Add a new Android Layout to the Resources/Layout folder, FirstView.axml
  31. TipCalc.Droid: You may run into an error: “error XA4210: You need to add a reference to Mono.Android.Export.dll when you use ExportAttribute or ExportFieldAttribute.” If you do, you just need to Add Reference to Mono.Android.Export (search in the Add Reference dialog).
  32. TipCalc.iOS: Update AppDelegate class to inherit from MvxApplicationDelegate, and remove the default code.
    [Register("AppDelegate")]
    public class AppDelegate : MvxApplicationDelegate<MvxIosSetup<App>, App>
    {
    }
  33. TipCalc.iOS: Add an Empty Storyboard, called Main.storyboard, to the root of the project
  34. TipCalc.iOS: Add a ViewController to the Main.storyboard using the designer and set the Class and Storyboard ID to FirstView (also make sure the “User Storyboard ID” checkbox is set to true)
  35. TipCalc.iOS: Move the generated FirstView.cs and FirstView.designer.cs files (from the previous step) into a new folder called Views, and adjust the namespace of the FirstView class to FirstView.iOS.Views
  36. TipCalc.iOS: Update the FirstView class to inherit from MvxViewController
    [MvxFromStoryboard("Main")]
    public partial class FirstView : MvxViewController<FirstViewModel>


Now to actually build out the Tip Calculator. Rather than embed the calculation logic into our view model, we’re going to abstract it out into a service. To do this we’ll make use of the IoC container made available by MvvmCross. We’ll register a CalculationService which will be injected into our view model constructor.

Let’s continue our development of the Tip Calculator in TipCalc.Core:

  1. Add a folder called Services
  2. Add an interface ICalculationService into the Services folder
    public interface ICalculationService
    {
         double Tip(double subTotal, double generosity);
    }
  3. Add a class, CalculationService, which implements ICalculationService, again into the Services folder
    public class CalculationService : ICalculationService
    {
         public double Tip(double subTotal, double generosity)
         {
             return subTotal * generosity / 100.0;
         }
    }

  4. Add a constructor to the FirstViewModel which accepts an ICalculationService parameter
  5. private readonly ICalculationService _calculationService;
    public FirstViewModel(ICalculationService calculationService)
    {
         _calculationService = calculationService;
    }

  6. Add properties for SubTotal, Generosity, Tip and Total. Each property should take the following form where SetProperty is called within the setter
    private double _subTotal;
    public double SubTotal
    {
         get { return _subTotal; }
         set { SetProperty(ref _subTotal, value); }
    }
  7. Add a Recalc method which will invoke the Tip method on the ICalculationService
    private void Recalc()
    {
         Tip = _calculationService.Tip(SubTotal, Generosity);
         Total = SubTotal + Tip;
    }
  8. Add a call to Recalc into the setter for both SubTotal and Generosity
  9. Set some initial values for the SubTotal and Generosity (if you use the property setters, rather than setting the fields, the Recalc method will be invoked)

That’s it for the core logic for the application. Now we just need to wire up the UI for each platform.

One thing that’s worth noting is that in step 16 of the original setup where the Initialize method is overridden, there is logic in the Initialize method to interrogate the current assembly looking for all classes that end in Service and register them, based on their interface, with the MvvmCross IoC container – this is how MvvmCross knows about the implementation of the ICalculationService which is used when instantiating the FirstViewModel.

Let’s built out the UWP interface in TipCalc.Uwp:

  1. Add the following XAML inside the existing Grid element:
    <StackPanel>
         <TextBlock Text="SubTotal"/>
         <TextBox Text="{Binding SubTotal, Mode=TwoWay}"/>
         <TextBlock Text="How generous?"/>
         <Slider Value="{Binding Generosity, Mode=TwoWay}"
                 Minimum="0"
                 Maximum="100"/>
         <TextBlock Text="Tip:"/>
         <TextBlock Text="{Binding Tip}"/>
         <TextBlock Text="SubTotal:"/>
         <TextBlock Text="{Binding Total}"/>
    </StackPanel>

That’s the UWP interface done – four elements (with TextBlock headings): TextBox and Slider for inputting SubTotal and Generosity using two-way data binding, and two TextBlock for outputting the Tip and Total amounts.

Now let’s do Android:

  1. Add the following namespace declaration to FirstView.axml
    xmlns:local="http://schemas.android.com/apk/res-auto"
  2. Add the following xml to FirstView.axml
    <TextView
         android:text="SubTotal"
         android:textAppearance="?android:attr/textAppearanceMedium"
         android:layout_width="fill_parent"
         android:layout_height="wrap_content"
         android:id="@+id/textView1" />
    <EditText
         android:layout_width="fill_parent"
         android:layout_height="wrap_content"
         android:id="@+id/editText1"
         local:MvxBind="Text SubTotal" />
    <TextView
         android:text="Generosity"
         android:textAppearance="?android:attr/textAppearanceMedium"
         android:layout_width="fill_parent"
         android:layout_height="wrap_content"
         android:id="@+id/textView2" />
    <SeekBar
         android:layout_width="fill_parent"
         android:layout_height="wrap_content"
         local:MvxBind="Progress Generosity"
         android:id="@+id/seekBar1" />
    <TextView
         android:text="Tip"
         android:textAppearance="?android:attr/textAppearanceMedium"
         android:layout_width="fill_parent"
         android:layout_height="wrap_content"
         android:id="@+id/textView3" />
    <TextView
         android:textAppearance="?android:attr/textAppearanceMedium"
         android:layout_width="fill_parent"
         android:layout_height="wrap_content"
         local:MvxBind="Text Tip"
         android:id="@+id/textView4" />
    <TextView
         android:text="Total"
         android:textAppearance="?android:attr/textAppearanceMedium"
         android:layout_width="fill_parent"
         android:layout_height="wrap_content"
         android:id="@+id/textView5" />
    <TextView
         android:textAppearance="?android:attr/textAppearanceMedium"
         android:layout_width="fill_parent"
         android:layout_height="wrap_content"
         local:MvxBind="Text Total"
         android:id="@+id/textView6" />

In this case we’re leveraging the xml extensions offered by MvvmCross in order to do the data binding using the MvxBind syntax.

Finally, let’s do iOS:

  1. Add the following code to the FirstView.cs
    public override void ViewDidLoad()
    {
         base.ViewDidLoad();
  2.     // Perform any additional setup after loading the view
         var label = new UILabel(new RectangleF(10, 0, 300, 40));
         label.Text = "SubTotal";
         Add(label);

        var subTotalTextField = new UITextField(new RectangleF(10, 40, 300, 40));
         Add(subTotalTextField);

        var label2 = new UILabel(new RectangleF(10, 80, 300, 40));
         label2.Text = "Generosity?";
         Add(label2);

        var slider = new UISlider(new RectangleF(10, 120, 300, 40));
         slider.MinValue = 0;
         slider.MaxValue = 100;
         Add(slider);

        var label3 = new UILabel(new RectangleF(10, 160, 300, 40));
         label3.Text = "Tip";
         Add(label3);

        var tipLabel = new UILabel(new RectangleF(10, 200, 300, 40));
         Add(tipLabel);

        var label4 = new UILabel(new RectangleF(10, 240, 300, 40));
         label4.Text = "Total";
         Add(label4);

        var totalLabel = new UILabel(new RectangleF(10, 280, 300, 40));
         Add(totalLabel);

       var set = this.CreateBindingSet<FirstView, FirstViewModel>();
         set.Bind(subTotalTextField).To(vm => vm.SubTotal);
         set.Bind(slider).To(vm => vm.Generosity);
         set.Bind(tipLabel).To(vm => vm.Tip);
         set.Bind(totalLabel).To(vm => vm.Total);
         set.Apply();

    }

In this case for iOS we again make use of the data binding support provided by MvvmCross by using the CreateBindingSet method, followed by a call to Bind for each element property we want to bind, and then finally a call to Apply to complete the setup of data binding.

And that’s it – a Tip Calculator for all three platforms.

MVX=0F Side Note: Adding a Splash Screen

I received some feedback on my previous post on setting up MvvmCross for Xamarin.Forms, asking how to add a splash screen to the Android Forms application. In the post MVX=0 I converted the MainActivity that comes as part of the standard Xamarin Android project into a SplashScreen but when it came to the Android project for Xamarin.Forms I left it without a splash screen.

Luckily adding a splash screen is really easy, so let’s add one to the Forms.Droid project:

  1. Copy the SplashScreen.axml from the /Resources/layout folder in the FirstDemo.Droid project into the /Resources/layout folder in the Forms.Droid project
  2. Remove “MainLauncher = true” from the Activity attribute on the MainActivity
  3. Change the MainActivity inheritance:
    public class MainActivity : MvxFormsAppCompatActivity<MainViewModel>
  4. Add a new class, SplashScreen.cs:
    [Activity(Label = "FirstDemo.Forms.Splash", Theme = "@style/MainTheme", MainLauncher = true, NoHistory = true)]
    public class SplashScreen : MvxFormsSplashScreenAppCompatActivity<MvxFormsAndroidSetup<Core.App, App>, Core.App, App>
    {
         public SplashScreen() : base(Resource.Layout.SplashScreen)
         {
         }
  5.     protected override void RunAppStart(Bundle bundle)
         {
             StartActivity(typeof(MainActivity));
             base.RunAppStart(bundle);
         }
    }

And there you have it – the Android Xamarin.Forms project will launch with a splash screen before redirecting to the MainActivity which will host the Xamarin.Forms content.

MVX=0F: A first MvvmCross Application (MVX+1 days of MvvmCross)

Updated 16/4/2018: Reference to MvvmCross have been updated to v6.0.0

One of the awesome things about MvvmCross is that you can take the exact same set of ViewModels that you used for your UWP, iOS, Android applications and use them in a Xamarin Forms application. As we go through the MVX+1 series, I’ll make some space for talking about Xamarin Forms as well.

In this post we're going to extent what we started in the previous post by adding a Xamarin Forms interface – this means creating new head projects for iOS, Android and UWP too. All up we’re adding four new projects but fear not, most of the heavy lifting is done by Visual Studio:

Into our existing solution we’re going to add a new Xamarin Forms project:

  1. Add a new Mobile App (Xamarin.Forms) project called FirstDemo.Forms
    image_thumb1_thumb
  2. When prompted, select Blank App, make sure all three Platforms are checked and make sure you select the .NET Standard option (Do NOT use the Share Project option).
    image_thumb3_thumb
  3. Upgrade the Xamarin.Forms NuGet to latest for all four Forms projects (at time of writing is 2.5.1.444934)
  4. Add MvvmCross NuGet Package to all Forms projects (Forms, Forms.iOS, Forms.Android and Forms.UWP)
  5. Add MvvmCross.Forms NuGet Package to all Forms projects (Forms, Forms.iOS, Forms.Android and Forms.UWP)

Note: You may need to upgrade to latest NuGet packages for all Forms projects before you can add references to the MvvmCross packages.

Update the FirstDemo.Forms project

  1. Remove all code in App class except for constructor with a call to InitializeComponent
  2. Create Views folder
  3. Move MainPage into Views folder and rename to FirstView
  4. Adjust FirstView.xaml and FirstView.xaml.cs to change class name to FirstView and to make it inherit from MvxContentPage
  5. Add two Entry and a Label with data binding to FirstView.xaml


Update the FirstDemo.Forms.Uwp project

  1. Update Microsoft.NETCore.UniversalWindowsPlatform (v6.0.8 at time of writing)
  2. Add reference to FirstDemo.Core
  3. Change MainPage to inherit from MvxFormsWindowsPage
  4. Remove all code other than the InitializeComponent method call in the constructor of MainPage
  5. Add ProxyMvxApplication
    public abstract class ProxyMvxApplication : MvxWindowsApplication<MvxFormsWindowsSetup<Core.App, FirstDemo.Forms.App>, Core.App, FirstDemo.Forms.App, MainPage>
  6. Change App.xaml and App.xaml.cs to inherit from ProxyMvxApplication
  7. Remove all code other than the constructor, with a single call to InitializeComponent, in App.xaml.cs

Update the FirstDemo.Forms.Android project

Note (1): If you run into the following error, you may need to rename your project. In this case we renamed it to Forms.Droid (as well as the folder the project resides in)
1>C:\Program Files (x86)\Microsoft Visual Studio\Preview\Enterprise\MSBuild\Xamarin\Android\Xamarin.Android.Common.targets(2088,3): error MSB4018: System.IO.PathTooLongException: The specified path, file name, or both are too long. The fully qualified file name must be less than 260 characters, and the directory name must be less than 248 characters.

Note (2): If you’re using the preview build of Visual Studio, you may run into an error: “error XA4210: You need to add a reference to Mono.Android.Export.dll when you use ExportAttribute or ExportFieldAttribute.” If you do, you just need to Add Reference to Mono.Android.Export (search in the Add Reference dialog).

  1. Change Forms.Android project to target latest Android SDK (v8.1 at time of writing)
  2. Upgrade Xamarin.Android.Support.* to latest for the Forms.Android project
  3. Add reference to FirstDemo.Core
  4. Change MainActivity inheritance, remove code except for a constructor:
    public class MainActivity : MvxFormsAppCompatActivity<MvxFormsAndroidSetup<Core.App, App>, Core.App, App>
    {
    }

Update the FirstDemo.Forms.iOS project

  1. Add reference to FirstDemo.Core
  2. Changed inheritance of AppDelegate
    public partial class AppDelegate : MvxFormsApplicationDelegate<MvxFormsIosSetup<Core.App, FirstDemo.Forms.App>, Core.App, FirstDemo.Forms.App>

And there you have it – you should be able to build and run all three Forms projects utilising the same view models that the non-Forms projects used

MVX=0 : A first MvvmCross Application (MVX+1 days of MvvmCross)

[Repost: Apologies for those who have already read this but there were some issues with the link generated for the previous post, so I’ve reposted it]

Updated 16/4/2018: Reference to MvvmCross have been updated to v6.0.0

Yes, this is going to be a sequence of posts reworking the infamous N+1 series that Stuart Lodge did starting almost exactly 5 years ago. As we approach the 5 year anniversary of these posts I thought it only fitting to cover this series again as a way of introducing MvvmCross v6 which will be released very shortly has just been released. Unlike the original series that were YouTube videos accompanied by blog posts, this series will only contain the posts, mainly because I find generating videos to be time consuming. Anyhow, here goes:

We’ll start by creating a Blank Solution.

image_thumb4_thumb

Into the solution we’ll add a Core Library that will contain an App class and our first ViewModel:

  1. Add a Class Library (.NET Standard) called FirstDemo.Core
    image_thumb3_thumb
  2. Add a reference to MvvmCross NuGet package (v6.0.0-beta.8 v6.0.0 at time of writing)
  3. Rename the default Class1.cs to App.cs, and allow Visual Studio to rename class to App
  4. Change App to inherit from MvxApplication
  5. Add a folder, ViewModels, and add a class called FirstViewModel.
  6. Change FirstViewModel to inherit from MvxViewModel
  7. Add logic to FirstViewModel to include FirstName, LastName and a calculated FullName
  8. Override Initialize method in App to call RegisterAppStart, specifying FirstViewModel as the startup ViewModel

Let’s start with a Universal Windows Platform UI:

  1. Add a Blank App (Universal Windows) called FirstDemo.Uwp
    image_thumb6_thumb
  2. Make sure Minimum and Target versions are set to at least the Fall Creators Update so that it supports .NET Standard 2.0
    image_thumb8_thumb
  3. Update NuGet package Microsoft.NETCore.UniversalWindowsPlatform to the latest stable version (6.0.8 at time of writing)
  4. Add a reference to MvvmCross NuGet package
  5. Add reference to FirstDemo.Core project
  6. Add a help class ProxyMvxApplication to the FirstDemo.Uwp project – this is a proxy class to compensate for the lack of generics support in XAML
  7. public abstract class ProxyMvxApplication: MvxApplication<MvxWindowsSetup<Core.App>, Core.App> { }

  8. Change App.xaml and App.xaml.cs to inherit from ProxyMvxApplication
  9. Remove all code in App.xaml.cs other than the constructor which should contain a single call to InitializeComponent
  10. Delete MainPage.xaml and MainPage.xaml.cs
  11. Add a Views folder, and  add a FirstView based on the Blank XAML page template
  12. Change FirstView.xaml and FirstView.xaml.cs to inherit from MvxWindowsPage
  13. Add some TextBoxes and a TextBlock to the FirstView, complete with databinding
  14. Hit F5 and run the application (you may have to set the FirstDemo.Uwp project as the startup project and make sure it’s set to build and deploy using the Configuration Manager)

Next let’s add the Android UI:

  1. Add a Android App (Xamarin) called FirstDemo.Droid
    image_thumb10_thumb
  2. Select the Blank App template, and the minimum Android version
  3. Update the Xamarin.Android.Support.Design NuGet package (at time of writing the latest is 27.0.2)
  4. Update the Android version to Use Latest Platform
    image_thumb12_thumb
  5. Add a reference to MvvmCross NuGet package
  6. Add a reference to MvvmCross.Droid.Support.V7.AppCompat package
  7. Add reference to FirstDemo.Core project
  8. Add a new class, MainApplication, that inherits from MvxAppCompatApplication
    public class MainApplication : MvxAppCompatApplication<MvxAppCompatSetup<App>, App>
  9. Rename MainActivity.cs to SplashScreen.cs and let Visual Studio rename the class
  10. Rename activity_main.axml to SplashScreen.axml, and adjust layout to indicate application loading
  11. Adjust SplashScreen class to inherit from MvxSplashScreenAppCompatActivity and set NoHistory to true (since we don’t want the user to be able to press the back button and go back to the splash screen)
  12. [Activity(Label = "@string/app_name", Theme = "@style/AppTheme", MainLauncher = true, NoHistory = true)]
    public class SplashScreen : MvxSplashScreenAppCompatActivity

  13. Add a folder, Views, and add a new Activity, FirstView.cs
    1. Add a new Android Layout to the Resources/Layout folder, FirstView.axml, with a couple of EditText and a TextView, all data bound using MvxBind
    2. You may run into an error: “error XA4210: You need to add a reference to Mono.Android.Export.dll when you use ExportAttribute or ExportFieldAttribute.” If you do, you just need to Add Reference to Mono.Android.Export (search in the Add Reference dialog).
    3. Set the startup project to be FirstDemo.Droid and press F5 to run the application

    Lastly, let’s add the iOS UI:

    1. Add an iOS App (Xamarin) called FirstDemo.iOS
      image_thumb2_thumb
    2. Select the Blank App template, Universal devices support and Minimum iOS Version of 11.2
      1. Add a reference to MvvmCross NuGet package
        1. Add reference to FirstDemo.Core project
        2. Update AppDelegate class to inherit from MvxApplicationDelegate
          public class AppDelegate : MvxApplicationDelegate<MvxIosSetup<App>, App>
        3. Add an Empty Storyboard, called Main.storyboard, to the root of the project
        4. Add a ViewController to the Main.storyboard using the designer and set the Class and Storyboard ID to FirstView (also make sure the “User Storyboard ID” checkbox is set to true)
        5. Move the generated FirstView.cs and FirstView.designer.cs files (from the previous step) into a new folder called Views, and adjust the namespace of the FirstView class to FirstView.iOS.Views
        6. Add two UITextField and a UILabel to the FirstView ViewController using the Main.storyboard designer (make sure each element has a Name set so it can be referenced from code)
        7. Update the FirstView class to inherit from MvxViewController
          [MvxFromStoryboard("Main")]
          public partial class FirstView : MvxViewController<FirstViewModel>
        8. Add logic to FirstView to enable databinding using the CreateBindingSet extension method
        9. Set the startup project to be FirstDemo.Droid and press F5 to run the application
          Update 16/4/2018: For some reason the iOS App (Xamarin) project template still uses a package.config. During the update to the stable v6.0.0 package the package.config file in FirstDemo.iOS was removed, the reference in FirstDemo.iOS.csproj to MvvmCross was manually removed and the following ItemGroup added:
          <ItemGroup>
             <PackageReference Include="MvvmCross" Version="6.0.0" />
          </ItemGroup>

        The final code is available at https://github.com/nickrandolph/MvxPlus1DaysOfMvvmCross/tree/master/Mvx-00-FirstDemo

        To get this to work I would suggest running the latest Visual Studio for Mac or PC. Hit me up on Twitter or Slack if you have any issues following the steps or running the samples.

        New BuildIt Release for NetStandard 2.0 (General, States and Forms)

        A new release of the following libraries is available via NuGet (v1.1.0.134):

        - BuildIt.General

        - BuildIt.States

        - BuildIt.Forms

        Whilst not much has changed in terms of features, behind the scenes there was quite a significant change as we adjusted the solution/project structure, and thus the nuget package structure. We took advantage of the ability to multi-target which meant we no longer have to have separate projects/libraries in order to support platform specific features. BuildIt.General, which used to have a UWP specific library, is now a single libary. Same goes for BuildIt.States. BuildIt.Forms has two libraries, down from the 5 that it used to have.

        Additionally we also added direct support for netstandard 2.0. As part of the build process, each library is compiled for netstandard 1.0, netstandard 2.0 and then any platforms that have additional features.

        In this release we’ve released multiple packages with the same version number, even though there is an interdependency between them (Forms –> States –> General).

        Please reach out and let me know if you see any issues in this release with any of these libraries. We’ll be working to release updates to the other BuildIt libraries over the coming weeks.

        Building Applications for Platform X

        As we get started with a new year it’s time to pause and think about how the app development ecosystem has evolved, what technologies continue or are emerging, and look at the decision matrix that will define what technology your next application is developed in. I’m going to treat this post as a bit of an intro to some of the technologies that I think are worth further investigation.

        I think the easiest way to do this is to walk the spectrum from web apps through to native platform apps:

        Web Apps

        When we talk about web apps, there is a natural assumption that these will be responsive web sites that will work across a wide range of devices and browsers. However, they can be divided further into what I would consider traditional web sites and single page applications. Whilst this division can be blurred, for example when you host an Angular application within a .NET core application, the point is that there is a difference in the mindset of the developers building the web app.

        Of course, this section includes the obvious ASP.NET Core, React and Angular. Whilst ASP.NET is still a valid choice, I specifically left it out of the list as I think most new projects will favour ASP.NET Core unless there is an impediment that requires full ASP.NET.

        Progressive Web Applications allow web developers to extend their applications to leverage more device capabilities. This is a particularly hot area of development for most platforms as this is seen as one of the best long term solution for minimising mobile development fatigue.

        Hybrid

        Next in the progression are hybrid applications which combine web technologies with a platform specific deployment package – this sounds a bit cryptic but that’s because there are a couple of different models for this.

        Firstly there’s the Cordova/PhoneGap model where the application is defined using html, css, javascript, and wrapped in a native platform deployment package. The deployment step is required in order for most stores to accept applications. The important thing here is that the layout and logic for the application is packaged with the application and that the platform web rendering engine is used to display the application.

        The second model is much more interesting and is one that’s being used by React Native and Native Script where the logic and layout is defined in javascript, css and a form of HTML. The HTML actually defines native elements that will be rendered in the correct location.

        Cross Platform

        Before we get to native platform tools and technologies, we’ll stop in on a long time friend, Xamarin. As with the previous sections there are again two options with Xamarin: traditional Xamarin, and Xamarin Forms. With the traditional Xamarin approach the developer is much closer to the metal and has a higher degree of control. However, the Xamarin Forms option allows for user interfaces to be rapidly developed once, and then feedback/issues are resolved on a platform by platform basis.

        Native Platform

        Lastly, we have the Native platform options for developers:

        Android

        Java, C++ with Eclipse, Android Studio

        iOS

        Objective C, Switft, Interface Builder (now part of XCode)

        UWP

        C#, XAML, Visual Studio (or Visual Studio for Mac)

        As this is hopefully one in a sequence of posts on the topic of framework selection, I’d love some feedback on what technology you think will be important to you and those you work with – comments are off but hit me up on twitter @thenickrandolph if you have thoughts on this.

        Making MvvmCross with Xamarin Forms Friction Free

        My last two posts (part 1 and part 2) outlined all the steps necessary to get a new Xamarin Forms with MvvmCross project setup. What I thought was going to be a simple post ended up being much longer due to all the unnecessary steps to setup both Xamarin Forms and MvvmCross. I’ve recently been contributing a little to MvvmCross and one of my concerns with it is that there are just way to many things that you need to get right in order to get it to work nicely with Xamarin Forms. If you don’t follow one of the introductory posts, such as the one provided by Martjin van Dijk, you’ll probably start hacking around with the numerous extension points in order to get it to work. I spent time over the last day seeing if I could reduce this initial friction to getting started.

        When you adopt a framework, or any library for that matter, you do so to reduce the need to reinvent the wheel – there’s no point in recreating, or creating something new, if there are existing solutions available. However, I’m of the opinion that you should be able to determine how much the framework influences the way that your code is structured. You should only have to modify your code if the framework offers a clear advantage. If we do a quick review of some of the changes required to take advantage of MvvmCross in our Xamarin Forms project you’ll see that quite a few of these are artificial requirements, mandated by the current MvvmCross implementation, rather than for any specific need. Here are just a couple:

        • App needs to inherit from MvxFormsApplication – this doesn’t add anything other than a couple of events, so unless you want to use those events, this is unnecessary
        • All pages need to inherit from the Mvx equivalent (eg MvxContentPage instead of ContentPage) – the Mvx equivalent expose a ViewModel property which can be useful but is not required in order to take advantages of data binding to the corresponding ViewModel since all Forms elements have a BindingContext that’s used for this purpose. The actual requirement here is for views/pages to implement IMvxView but unless you need the ViewModel property this shouldn’t be a requirement.
        • You need to create a class that inherits from MvxApplication which can do things like register services but most importantly defines what the starting ViewModel is going to be. This is kind of unnecessary if the only thing that it’s doing is defining the starting ViewModel, although I do understand the desire to have the starting ViewModel defined somewhere that is independent of the head projects.
        • All ViewModels need to inherit from MvxViewModel or implement IMvxViewModel – again this is somewhat unnecessary since ViewModels should just be a regular class. Now I do agree that in most cases your ViewModel is likely to implement INotifyPropertyChanged, so this additional requirements isn’t a massive addition but needless to say it shouldn’t be a requirement.

        Ok, so after a bit of experimenting without modifying MvvmCross or MvvmCross.Forms (ie I’m just using the NuGet packages) what I came up with is BuildIt.MvvmCross.Forms (currently in prerelease!) which is a NuGet package which adds a couple of helper classes to get you going just that bit quicker. Here are the steps to get started using BuildIt.MvvmCross.Forms:

        Start by following the steps outlined in part 1 – this will give you a Xamarin Forms project that’s completely up to date. I’ll call this project LowFriction

        Next, follow the early steps in part 2 to add an additional project for your ViewModels, LowFriction.Core, and subsequently add references to MvvmCross (to all projects) and MvvmCross.Forms (to all projects except the Core project).

        Add a reference to the BuildIt.MvvmCross.Forms NuGet package to all projects except the Core project. A primary requirement here is that the Core project should not have a reference to the view technology, which in this case is Xamarin Forms – if you find yourself adding a reference (directly or otherwise) to Xamarin Forms to your Core project, you’ve done something wrong and you should rethink the decisions that led you to that point.

        You still need to change App.xaml to inherit from MvxFormsApplication – I couldn’t find a work around this requirements

        Your pages do not need to change to implement iMvxView – MainPage inherits from ContentPage

        In your Core project you will need to create ViewModels that map to your pages, and they need to implement iMvxViewModel – again I couldn’t find a work around for this requirement. MainViewModel inherits from MvxViewModel.

        In your Core project you do not  need to create a class that inherits from MvxApplication – we’ll come to this later but essentially BuildIt.MvvmCross.Forms has class called TypedMvxApplication whose type parameter is the starting ViewModel. If you do want to extend the MvxApplication you can still create your own application but I would recommend using TypedMvxApplication as a starting point

        UWP

        In App.xaml.cs replace

        Xamarin.Forms.Forms.Init(e);

        with

        var setup = new SetupFromViewModel<MainViewModel, LowFriction.App>(rootFrame, e);
        setup.Initialize();

        You can see here that the SetupFromViewModel class accepts the starting ViewModel as a parameter. If you’d prefer to define the starting ViewModel in the Core project I recommend defining a class that inherits from TypedMvxApplication, specify the starting ViewModel as the type parameter, and then use the SetupFromApplication class in App.xaml.cs.

        Change MainPage to inherit from BuildIt.MvvmCross.Forms.UWP.MvxFormsWindowsPage (I also updated the layout of MainPage to show some data coming from databinding from the ViewModel, similar to what I did in my previous post)

        Change the MainPage constructor to

        public MainPage()
        {
             this.InitializeComponent();

            MvxLoadApplication();
        }

        Android

        Change MainActivity to inherit from CustomMvxFormsAppCompatActivity<SetupFromViewModel<MainViewModel, LowFrictionApp>, MainViewModel>

        Comment out the Xamarin Forms init code:

        //global::Xamarin.Forms.Forms.Init(this, bundle);
        //LoadApplication(new App());

        iOS

        Change AppDelegate to inherit from CustomMvxFormsApplicationDelegate

        Change FinishedLaunching

        public override bool FinishedLaunching(UIApplication app, NSDictionary options)
        {
             Window = new UIWindow(UIScreen.MainScreen.Bounds);

            var setup = new SetupFromViewModel<MainViewModel, App>(this, Window);
             setup.Initialize();

            MvxLoadApplication();

            Window.MakeKeyAndVisible();

            //global::Xamarin.Forms.Forms.Init();
             //LoadApplication(new App());

            return base.FinishedLaunching(app, options);
        }

        And we’re done! Build and run on each platform and you should be good to go.

        As you can see there are significantly fewer steps involved in getting started, and few additional classes to be created. I do note that there is still room for improvement and I feel that as frameworks go MvvmCross has been developed with extensibility in mind – which is why I was able to streamline the getting started experience so much.

        Getting Started: MvvmCross with Xamarin Forms (Part 2)

        In my previous post I covered the first part of this post on Getting Started with MvvmCross and Xamarin Forms where I covered the initial steps in getting a new Xamarin Forms project started. In this post I’m going to continue on and show how you can configure a Xamarin Forms solution to make use of MvvmCross.

        Before I get started with MvvmCross I’m going to add a new project which will contain all my ViewModels. Whilst not entirely necessary, particularly with Xamarin Forms where the views/pages are in a .NET Standard library, it’s good practice to completely separate your ViewModels away from the views/pages to avoid any accidental interdependencies forming. I’ll add a new project based on the .NET Standard class library template.

        image_thumb11[1]

        For this library I’m going to adjust the .NET Standard version back to 1.0 – I prefer to start with a low .NET Standard version and increase it only when I need to take advantage of features in the higher versions. This ensures that the library can be referenced by the widest set of targets platforms.

        image_thumb11

        I’ll add a reference to the new project to each of the other projects in the solution.

        image_thumb31

        The next step is to add a reference to the MvvmCross NuGet package. Currently MvvmCross is still distributed as a set of Portable Class Libraries and if we attempt to add the NuGet package to either our MvvmcrossGettingStarted or MvvmcrossGettingStarted.Core projects, we’ll get an error as they’re both .NET Standard library. What’s annoying about this is that the MvvmCross PCLs are fully compatible with .NET Standard, meaning that it should be possible to add a reference to them. Unfortunately Visual Studio isn’t clever enough to be able to resolve this, and as such we need to adjust the csproj files for both projects before attempting to add a reference to MvvmCross.

        Add the following line into the first PropertyGroup of the csproj files for both MvvmcrossGettingStarted or MvvmcrossGettingStarted.Core projects. One saving grace is that it’s now easy in Visual Studio to edit a csproj by right-clicking on the project and selecting “Edit <project name>.csproj”.

        <PackageTargetFallback>$(PackageTargetFallback);portable-net45+win8+wpa81</PackageTargetFallback>

        Eg.

        image_thumb23

        Next we can go ahead and add a reference to MvvmCross to all our projects. Right-click on the solution node in Solution Explorer and select Manage NuGet Packages for Solution, and then search for mvvmcross. Select the most recent stable version of MvvmCross (this image is a little old as the version is at 5.6.3 at time of writing this)

        image_thumb9

        In addition to the main MvvmCross package, we also want to add in the Xamarin Forms support library, MvvmCross.Forms. Note that we do not add this to the MvvmcrossGettingStarted.Core project – this is the separation of concerns we setup at the beginning of this post to ensure there is no dependencies on the viewing technology within our ViewModels.

        image_thumb21

        Now that we have added the references to MvvmCross there are a bunch of small changes we need to apply to our application in order to get it all up and running. We’ll start in the MvvmcrossGettingStarted.Core project where we need to create two classes.

        The first class we’ll create inherits from MvxApplication and is used to setup the application within the ViewModel world. MvvmCross has an opinionated navigation model whereby navigation is defined at a ViewModel level, and simply implemented at a View level. As such the MvxApplication class, in this case GettingStartedApplication, defines the first ViewModel for the application.

        public class GettingStartedApplication : MvxApplication
        {
             public override void Initialize()
             {
                 RegisterNavigationServiceAppStart<MainViewModel>();
             }
        }

        The second class is the ViewModel that matches the first view or page of the application. MainPage was created back when we created the Xamarin Forms application, so we’ll create a class called MainViewModel. Whilst you can override the default view to viewmodel mapping in MvvmCross, it’s preconfigured to align views and viewmodels based on a naming convention. I typically stick with XXXViewModel and XXXPage but XXXView is also supported out of the box.

        In this case MainViewModel exposes a simple property that we’ll data bind to later to show that the Page and ViewModel have been glued together correctly.

        public class MainViewModel: MvxViewModel
        {
             public string WelcomeText => "Welcome to my data bound Xamarin Forms + MvvmCross application!";
        }

        Now we’ll switch over to the MvvmcrossGettingStarted project and make some changes to both the App and MainPage classes.

        In the App.xaml, we need to change the root element to reference MvxFormsApplication

        <?xml version="1.0" encoding="utf-8" ?>
        <mvx:MvxFormsApplication xmlns="
        http://xamarin.com/schemas/2014/forms"
                             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
                             xmlns:mvx="clr-namespace:MvvmCross.Forms.Platform;assembly=MvvmCross.Forms"
                            
        x:Class="MvvmcrossGettingStarted.App">
             <Application.Resources>
             </Application.Resources>
        </mvx:MvxFormsApplication>

        And in App.xaml.cs, remove the inheritance – the Microsoft templates insist on including the inheritance in both the xaml and xaml.cs files which is quite unnecessary and should be removed.

        public partial class App
        {
             public App()
             {
                 InitializeComponent();
             }
        }

        We need to make a similar change to MainPage.xaml, changing the root element to MvxContentPage. We’ll also change the Label to use data binding to return the WelcomeText property from the MainViewModel.

        <?xml version="1.0" encoding="utf-8" ?>
        <mvx:MvxContentPage xmlns="
        http://xamarin.com/schemas/2014/forms"
                             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
                             xmlns:local="clr-namespace:MvvmcrossGettingStarted"
                             xmlns:mvx="clr-namespace:MvvmCross.Forms.Views;assembly=MvvmCross.Forms"
                            
        x:Class="MvvmcrossGettingStarted.MainPage">
             <Label Text="{Binding WelcomeText}"
                    VerticalOptions="Center"
                    HorizontalOptions="Center" />
        </mvx:MvxContentPage>

        Again, remove the inheritance specified in MainPage.xaml.cs

        public partial class MainPage
        {
             public MainPage()
             {
                 InitializeComponent();
             }
        }

        The next step involves adding a Setup class to each of the head projects, and then creating an instance of the Setup class to invoke MvvmCross when the application starts up.

        UWP

        The UWP Setup inherits from MvxFormsWindowsSetup and unlike the Android and iOS Setup classes, the UWP Setup needs to override the default log behaviour by setting the log provider type to None and then creating an instance of the EmptyVoidLogProvider  (the implementation of this is coming up soon) – this should be fixed in a future MvvmCross version.

        public class Setup : MvxFormsWindowsSetup
        {
             public Setup(Frame rootFrame, LaunchActivatedEventArgs e) : base(rootFrame, e)
             {
             }

            protected override MvxLogProviderType GetDefaultLogProviderType() => MvxLogProviderType.None;

            protected override IMvxLogProvider CreateLogProvider() => new EmptyVoidLogProvider();

            protected override IEnumerable<Assembly> GetViewAssemblies()
             {
                 return new List<Assembly>(base.GetViewAssemblies().Union(new[] { typeof(MvvmcrossGettingStarted.App).GetTypeInfo().Assembly }));
             }

            protected override MvxFormsApplication CreateFormsApplication() => new MvvmcrossGettingStarted.App();

            protected override IMvxApplication CreateApp() => new Core.GettingStartedApplication();
        }

        Now in App.xaml.cs we need to replace

        Xamarin.Forms.Forms.Init(e);

        with

        var setup = new Setup(rootFrame, e);
        setup.Initialize();

        And in Main.xaml.cs replace

        LoadApplication(new MvvmcrossGettingStarted.App());

        with

        var start = Mvx.Resolve<IMvxAppStart>();
        start.Start();

        var presenter = Mvx.Resolve<IMvxFormsViewPresenter>() as MvxFormsUwpViewPresenter;
        LoadApplication(presenter.FormsApplication);

        Finally, we need to add the EmptyVoidLogProvider

        public class EmptyVoidLogProvider : IMvxLogProvider
        {
             private readonly EmptyVoidLog voidLog;

            public EmptyVoidLogProvider()
             {
                 voidLog = new EmptyVoidLog();
             }

            public IMvxLog GetLogFor<T>()
             {
                 return voidLog;
             }

            public IMvxLog GetLogFor(string name)
             {
                 return voidLog;
             }

            public IDisposable OpenNestedContext(string message)
             {
                 throw new NotImplementedException();
             }

            public IDisposable OpenMappedContext(string key, string value)
             {
                 throw new NotImplementedException();
             }

            public class EmptyVoidLog : IMvxLog
             {
                 public bool Log(MvxLogLevel logLevel, Func<string> messageFunc, Exception exception = null, params object[] formatParameters)
                 {
                     return true;
                 }
             }
        }

        Now when we build and run the UWP project we can see that the MainPage is shown and is data bound to the MainViewModel.

        image

        iOS

        The iOS Setup is the simplest out of the three platforms.

        public class Setup : MvxFormsIosSetup
        {
             public Setup(IMvxApplicationDelegate applicationDelegate, UIWindow window)
                 : base(applicationDelegate, window)
             {
             }

            protected override IEnumerable<Assembly> GetViewAssemblies()
             {
                 return new List<Assembly>(base.GetViewAssemblies().Union(new[] { typeof(MvvmcrossGettingStarted.App).GetTypeInfo().Assembly }));
             }

            protected override MvxFormsApplication CreateFormsApplication() => new MvvmcrossGettingStarted.App();

            protected override IMvxApplication CreateApp() => new Core.GettingStartedApplication();
        }

        In AppDelegate we need to change the inheritance from  global::Xamarin.Forms.Platform.iOS.FormsApplicationDelegate to MvxFormsApplicationDelegate and change the FinishedLaunching method as follows:

        public override bool FinishedLaunching(UIApplication app, NSDictionary options)
        {
             Window = new UIWindow(UIScreen.MainScreen.Bounds);

            var setup = new Setup(this, Window);
             setup.Initialize();

            var startup = Mvx.Resolve<IMvxAppStart>();
             startup.Start();

            LoadApplication(setup.FormsApplication);

            Window.MakeKeyAndVisible();

            return base.FinishedLaunching(app, options);
        }

        Now we’re good to build and run the iOS project

        image

        Android

        Lastly, add Setup to the Android project. Note this is slightly different from the iOS and UWP projects in that the GetViewAssemblies method excludes the assembly for the Android head project. This is to avoid the MainActivity being added as a view, that based on our naming convention would match with MainViewModel giving a duplicate when attempting to resolve the View that should be rendered.

        public class Setup : MvxFormsAndroidSetup
        {
             public Setup(Context applicationContext) : base(applicationContext)
             {
             }

            protected override IEnumerable<Assembly> GetViewAssemblies()
             {
                 return new List<Assembly>(base.GetViewAssemblies()
                     .Union(new[] { typeof(MvvmcrossGettingStarted.App).GetTypeInfo().Assembly })
                     .Except(new[] {this.GetType().Assembly})
                     );
             }

            protected override MvxFormsApplication CreateFormsApplication() => new MvvmcrossGettingStarted.App();

            protected override IMvxApplication CreateApp() => new Core.GettingStartedApplication();
        }

        The MainActivity needs to be updated to change its inheritance from global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity to MvxFormsAppCompatActivity<MainViewModel>. And the OnCreate needs to be updated to

        [Activity(Label = "MvvmcrossGettingStarted", Icon = "@drawable/icon", Theme = "@style/MainTheme", MainLauncher = true, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation)]
        public class MainActivity : MvxFormsAppCompatActivity<MainViewModel>
        //global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity
        {
             protected override void OnCreate(Bundle bundle)
             {
                 TabLayoutResource = Resource.Layout.Tabbar;
                 ToolbarResource = Resource.Layout.Toolbar;

                base.OnCreate(bundle);

                var startup = Mvx.Resolve<IMvxAppStart>();
                 startup.Start();
                 InitializeForms(bundle);

             }
        }

        Finally the last platform, Android, is good to build and run. Note however that Android has a tendency to be a pain and that after setting everything up correctly you may still run into issues building, deploying and running. Before you waste hours looking at your code to see what you’ve done wrong, make the assumption that the tools are crap – delete both bin and obj folders from the Android head project, and uninstall the application from the device/emulator (assuming it has already been installed). Try building and running again – if this still fails, then you may indeed have something wrong with your code!

        image

        Getting Started: MvvmCross with Xamarin Forms

        Over the past 6-12 months we’ve seen dramatic changes in Xamarin Forms and the support within Visual Studio. The most recent update, which I covered in my previous post, included a number of new features for cross platform developers. However, despite these updates, getting started with cross platform development is still quite complex. In this post I wanted to take the opportunity to reiterate how to start a new Xamarin Forms project. From there I’ll cover adding in MvvmCross and discuss the importance of having a framework that will make development that much easier (for the record MvvmCross isn’t the only option, there are plenty of great alternatives such as Prism and FreshMvvm).

        Part 1: Getting Started with Xamarin Forms

        Before getting started, make sure you’ve run the Visual Studio Installer and have upgraded to the latest stable release of Visual Studio. The team at Microsoft have been putting a lot of focus on stability and performance, so upgrading to the latest version does help (still not perfect but a marked improvement over this time last year!). Upgrading Visual Studio continually can be a bit of a pain, especially since Microsoft haven’t quite worked out how to automatically download updates in the background for VS – meaning that you have to stop whatever you’re doing whilst the updates download and then install. Recommendation is to run the installer periodically at the end of your day, or when you’re heading to a long meeting; hopefully the installation is complete by the time you return.

        Now that you’re all up to date, let’s create a new solution by selecting the Cross-Platform App (Xamarin Forms) template from the New Project dialog. Note that if you don’t see this template, you may have to adjust the workloads you selected in the VS Installer so that you have all the cross-platform development components selected.

        image

        After clicking OK you should be presented with a second dialog that allows you to specify parameters for how your cross platform project should be setup. As you can see from the image, I recommend always selecting all three platforms (even if you’re only planning on targeting one or two of them initially); In this case we’re going with Xamarin.Forms with a simple Blank App; The last option I’m particularly passionate about – do NOT select Shared Project – for the good of your project, the team and general good programming practice, please select the .NET Standard option for Code Sharing Strategy. At time of writing the .NET Standard option is only available in the preview build of Visual Studio; the stable build uses a Portable Class Library, which is still preferable over using a Shared Project.

        image

        This time clicking OK will create a new solution.

        Unexpected Error when Creating Solution

        Unfortunately, at time of writing this post there is also a bug in the current cross platform template that results in the following error:

        image

        If you see this error, a quick Google will yield the following bugzilla issue (https://bugzilla.xamarin.com/show_bug.cgi?id=60995) which describes the issue, along with how to fix it yourself – you just need to edit the Android csproj file and remove the " from around the TargetFrameworkVersion ie:

        replace:

        <TargetFrameworkVersion>"v8.0"</TargetFrameworkVersion>

        with
        <TargetFrameworkVersion>v8.0</TargetFrameworkVersion>

        After fixing up the csproj file you’ll need to add the existing projects into the solution file.

        Assuming you didn’t run into any issues creating the solution, or you were able to fix up the Android csproj file, you should be able to build and run each of the head projects:

        UWP

        image

        Note: When building the UWP project I was seeing a build warning stating “warning APPX0108: The certificate specified has expired.” which I thought was a bit odd since I had just created the project and normally the certificate that is used for debug builds is created alongside the new project. Double-clicking the package.appxmanifest and switching to the Packaging tab I see that the Publisher display name isn’t set correctly – I’m guessing at this point that the cross platform template contains an existing certificate, instead of creating one each time. You can easily fix this by changing the publisher display name, clicking Choose Certificate and then from the dropdown select “Create test certificate”.

        image

        Now when you build the project you won’t see this warning – I’m guessing this is also a bug in the preview version of the cross platform template.

        Android

        image

        For Android I’m using the Google Android Emulator that can now be installed using the Visual Studio Installer. This is significantly better than it used to be, and the images are much more recent than those for the Visual Studio Android Emulator which has been deprecated now.

        iOS

        image

        For iOS, as I’m working from a Windows laptop, I use the Remote Simulator which works really well and means I don’t need to continually VNC to my MacMini or have to deploy to a real device.

        Again there was an issue with the iOS template in that the MinimumOSVersion was set to “11.2” instead of just 11.2 in the Info.plist file.

        <key>MinimumOSVersion</key>
        <string>11.2</string>

        Correcting the MinimumOSVersion will allow your application to run on a device or emulator.


        Now that we’ve validated that all the platforms run, it’s time to make sure they’re setup correctly ready for us to add in Mvvmcross and to set the foundation of our application. Android and iOS should be setup correctly, although you may want to double-check to make sure Android is set to use the latest platform version (see Application tab of the Android project properties); UWP defaults to using the Fall Creators Update (FCU) as the minimum version, which is way to recent for applications wanting to target the widest set of customers. Our preferences is to set this back to the November Update

        image

        Note however, that this does preclude your application from using .NET Standard 2.0 libraries, as these are not compatible with UWP projects prior to the FCU. Unfortunately the .NET Standard library that holds the Xamarin Forms views for the solution is set to .NET Standard 2.0 by default. This is completely unnecessary, so it can be reduced back to 1.4 (or below, depending on your preferences)

        image

        Next, we want to make sure we’re using the latest NuGet packages – right-click on the solution node in Solution Explorer and select Manage NuGet Packages for Solution

        image

        After upgrading all the NuGet packages, double-check to make sure all platforms build and run. Now’s a great time to check your solution in to your repository of choice (Note: make sure you check in the pfx file that is part of the UWP solution. You’ll probably have to manually add this file to your repository as most repositories ignore pfx files by default).

        Update: Part 2 is now available.

        Hey, who moved my… Visual Studio Emulator for Android?

        A while ago, in response to a common frustration from Xamarin developers, Microsoft released the Visual Studio Emulator for Android and it even made it into the Visual Studio installer:

        image

        As a long-serving Windows Phone developer I embraced this decision as the emulator was based on Hyper-V which meant that it played nicely with the Windows Phone emulators – I could now do cross platform development, even when I didn’t have real devices with me. Unfortunately, Microsoft have indicated that the emulator is no longer going to receive updates, so anyone wanting to dev/test on more recent builds of Android are out of luck. This was really frustrating as the emulator was both quick (relative to the out of the box emulators from Google – historically) and didn’t require another emulator sub-system (as it worked on Hyper-V).

        Recently, Microsoft have actively discounted Windows Phone, making it very hard to justify any developer resources on building for Windows Phone…. it also makes me question the value proposition of UWP over WPF, but that’s a topic for a different post. The upshot is that there is no longer a reason for me to have the Windows 10 Mobile emulators installed, which means I have no need for Hyper-V, which means I can use any one of the great Android emulators out there that don’t play nice wiht Hyper-V.

        What’s really cool is that Microsoft have included the Google Android Emulator in the Visual Studio installer. You need to make sure that both the Google Android Emulator and the Intel Hardware Accelerated Execution Manager are installed.

        image

        After installing the Google emulator you can launch your application on the emulator the same way you would to a real device – it appears in the devices dropdown. You can also access the different emulator images via the Android Emulator Manager.

        image

        Whilst the Android Emulator Manager is not a great looking dialog, it does allow you to customise and launch the different emulators.

        image

        I was so surprised when I launched the updated emulator. I was expecting an old, slow, crappy looking emulator but was surprised with an updated emulator shell with all the features that I’d come to expect from an emulator.

        image

        I’m a convert – Whilst I’ll still use a real device for most development work, having a good emulator is critical for those times when I don’t have a device with me. Cudos to Microsoft for firstly pushing Google to build a better developer experience and secondly making the Visual Studio installer so simple to install the emulator.

        Sidenote: I did have to update one component from the Android SDK. Make sure you read the build output window in Visual Studio if you are running into issues as it pointed me to an out of date component.