I’ve walked through this a couple of times in the past (last year and in the Mvx+1 series I started) but I wanted to do an updated post to firstly point out that the getting started process in Visual Studio has stabilized quite a lot and the process of getting a new Xamarin.Forms project up and running is quite smooth. The second thing I wanted to add is how, and why, you can setup your .NET Standard libraries to be multi-targeted – this also has come a long way.
Note: I’m running Visual Studio 15.8 preview 5, so your experience may vary a little if you’re running a different version of Visual Studio. Before I get started I try to make sure all my components are up to date, including my MacMini which is what I use for building/debugging iOS applications.
Let’s get started by creating a new solution within Visual Studio, using the Mobile App (Xamarin.Forms) project template
This will prompt you to select what template to use, in this case we’re going to create a project based on a Blank template. In actual fact this template isn’t blank; it has 1 page which is required in order for the application to build and run. Also, make sure you select the .NET Standard Code Sharing Strategy. DO NOT select Shard Project – this options in my opinion should now be deprecated as multi-targeting is a much better option for achieving this same outcome.
After clicking OK to create the project, you’ll want to make sure you can successfully build all projects.
Next open the NuGet package manager for the solution and update all packages to the latest stable. In my case I just had to update Microsoft.NETCore.UniversalWindowsPlatform and Xamarin.Forms.
Now, make sure that each platform (i.e. iOS, Android and UWP) compiles and runs. Technically you don’t need to do this but if you run into difficulty later, at least doing a run check here gives you a “last known good” state to revert to. On that note, after checking that each platform runs, I would be making the initial commit to source control for your solution.
Next we’re going to add a new project based on the Class Library (.NET Standard) project template. This will be our Core project that will contain all our view models, services and business logic for the application.
The new project will come with Class1. Rename both the file and class name to MainViewModel.
Next we’re going to do a bit of a tidy up. By default the project that contains the XAML for the application (i.e. App.xaml) and for the main page of the application (MainPage.xaml) was given the same name as the solution itself. I’m not a big fan of that so I rename this to have the UI suffix. To do this you need to remove the existing project, rename the folder and project name, and add the existing project back into the solution. Don’t forget that you’ll need to update the namespace for both App and MainPage classes (in both XAML and code behind files) to include UI (e.g. the full type name of the MainPage class should be StrataPark.UI.MainPage)
After renaming the UI project, we need to double check that all the projects have the correct references. The only project reference the UI project should have is to the Core project
All three of the head projects (i.e. for iOS, Android and UWP) should reference both the Core and UI projects
Now’s another time to check that everything builds and runs (all three platforms) and then commit your changes!
Both the Core and UI projects are currently just .NET Standard 2.0 projects. This means that all code is the same for all platforms. By making these projects multi-targeted, we can enable platform specific code to be included where necessary. This is similar to the way shared libraries used to work. However, the difference is that the code stays in a separate assembly, away from the head projects.
To make use of multi-targeting, first create a file called global.json in solution folder, with the following contents:
{ "msbuild-sdks": { "MSBuild.Sdk.Extras": "1.6.47" } }
The MSBuild.Sdk.Extras package extends the raw multi-targeting support provided by Visual Studio/MSBuild. For both Core and UI projects, edit the csproj and replace the default TargetFramework element at the beginning of the file with the following (make sure you include the Project element as this sets the Sdk to use)
<Project Sdk="MSBuild.Sdk.Extras"> <PropertyGroup> <TargetFrameworks>netstandard2.0;Xamarin.iOS10;MonoAndroid81;uap10.0.16299</TargetFrameworks> </PropertyGroup> <ItemGroup> <Compile Remove="Platforms\**\*.cs" /> <None Include="Platforms\**\*.cs" /> </ItemGroup> <ItemGroup Condition=" $(TargetFramework.StartsWith('netstandard')) "> <Compile Include="Platforms\Netstandard\**\*.cs" /> </ItemGroup> <ItemGroup Condition=" $(TargetFramework.StartsWith('uap')) "> <Compile Include="Platforms\Uap\**\*.cs" /> </ItemGroup> <ItemGroup Condition=" $(TargetFramework.StartsWith('Xamarin.iOS')) "> <Compile Include="Platforms\Ios\**\*.cs" /> </ItemGroup> <ItemGroup Condition=" $(TargetFramework.StartsWith('MonoAndroid')) "> <Compile Include="Platforms\Android\**\*.cs" /> </ItemGroup>
If you take a look at the code that was added to the csproj, you can see that there are some conditional inclusions based on the target platform. We’ll make use of this to return a platform specific welcome text for our application.
Add a Platforms folder to the Core project
Add Netstandard, Ios, Android and Uap sub-folders to the Platforms folder
Add a file called MainViewModel.Platform.cs to each sub-folder of the Platforms folder with the following text. Replace Netstandard with the name of the platform (i.e. the sub-folder name)
public partial class MainViewModel { private string PlatformWelcomeText => "Welcome from Netstandard"; }
Next, we’ll modify the MainViewModel.cs file. Note how the WelcomeText property returns the platform specific text
public partial class MainViewModel { public string WelcomeText => PlatformWelcomeText; }
In the MainPage.xaml, add a new Label element that is bound to the WelcomeText property
<Label Text="{Binding WelcomeText}" />
In the codebehind for the MainPage.xaml, add the following code to the end of the MainPage constructor
BindingContext = new MainViewModel();
Now when we build and run the application on each platform, we’ll see a platform specific welcome.
This technique can be used to include all sorts of platform specific code within your application, making it easier to deal with the Mvvm abstraction when you need to tie into platform specific APIs. In the past you’d have typically had to create a service in the head project, or some other clumsy workaround.
It’s not possible to have the same property “private string PlatformWelcomeText” in each folder with the same partial class and same namespace. How did you do it?
If you take a look at the csproj it starts by excluding (ie remove) all .cs files from the Platforms folder. Then for each target platform the appropriate platform specific folder is added eg Platforms\Ios\**\*.cs for iOS.
I did realise that when I migrated my blog across to WordPress the formatting on some of the code went wonky. Hopefully I’ve fixed this post up now and it should be easier to see why this works.
Yes, it was punctuation formatting problem. Now there are no errors. Great. Thanks.
I wonder how to run a netstandard application that display the “Welcome from Netstandard” message
You could reference it from a .net core console app. I think that should reference the .net standard library and thus give you the message. In practice with regards to using the library in apps, you shouldn’t see the .net standard message, except for a platform that you haven’t chosen to support (eg Tizen)
I already tested with the Xamarin-Forms-Gui.cs NuGet Package (https://github.com/jsuarezruiz/xamarin-forms-gui.cs) and I could see the .net standard message. Thanks