Multi-targeting .NET 4.6, .NET 4.7, UAP 10.0 with a single project

After waiting for the project.json storm to lay down, it was time for me to check whether the new .NET SDK project system was worth checking out. Oh dear, it was! In this post I will try to explain our reasoning to migrate to the new project system and how we overcame some of the issues we encountered during the transition.


One of the companies I work for use a large amount of (open source) libraries target .NET 4.5, .NET 4.6 and .NET 4.7. The reason we supported 3 different target frameworks per library is that it allowed us to switch the runtime of the (WPF) apps at any time and the libraries would be ready for it. However, a big downside of this is that loading the solution takes a long time, and everything is duplicated as you can see in the picture below:

While we are (considering to) making the transition to UWP, this would introduce a 4th platform project, meaning we would have 4 + 1 (for the shared project) = 5 projects per library.


Time to make a change! After reading the very promising blog post by Oren Novotny, I decided to make the jump and try and convert all the libraries to the new SDK project to achieve the following goals:

  • Single project to target multiple platforms (at the moment .NET 4.6, .NET 4.7, UAP 10.0 and .NET Standard 2.0, but more could easily be added in the future)
  • Update the build scripts from FinalBuilder to Cake (make it easier for open source contributors to work with)
  • Automatically generate the NuGet packages via MSBuild instead of FinalBuilder (again to make it easier for open source contributors to work with)

For this blog post, I will be using a fake repository named Ghk.MultiTargeting as an example. Note that this project is useless, but contains per-platform xaml code and shared code-behind.

Project differences compared to the original template

Compared to the original multi-targeting example, we made the following changes.

Project defines

To make sure I could still use the defines we invested in (to maximize code-sharing, we use a lot of #if in code shared between WPF and UWP). This project creates the following defines:

  • .NET 4.6 => NET; NET46
  • .NET 4.7 => NET; NET47
  • UAP 10.0 => UAP; NETFX_CORE
  • .NET Standard 2.0 => NS; NS20; NETSTANDARD; NETSTANDARD2_0

Include solution assembly info

The project structure adds this line to the project to include the SolutionAssemblyInfo and GlobalSuppressions files which are in the root of the solution.

Allow shared code-behind (e.g. MyView.xaml.cs) with a *per platform* view (e.g. MyView.xaml)

To allow sharing of code-behind of a view (for example, for custom controls), we need to to a bit of hacking. We create the view inside each platform specific view directory:

  • Platforms\net\Views\MyView.xaml (+ .cs)
  • Platforms\uap10.0\Views\MyView.xaml (+ .cs)

After creating the views, we will need to customize the code-behind to add a partial method:

Next, we create a partial code-behind class inside the regular views folder that contains the shared code:

  • Views\MyView.xaml.cs

This view should contain the following code and you can share your code-behind but have per-platform xaml files:

As an example, I added a dependency property in the shared code-behind that shows how to deal with the different platforms in shared code using defines.

Final project structure

Below is the final project structure that can serve as a reference.

Note that it is recommended to check out the latest version in the example repository.

Bonus: Cake deployments

Since we also migrated to using Cake as build script tooling, this is a good opportunity to take a look at Cake as well. I added the full build scripts we use for our components in the example repository. Note that you only have to change the variables in build.cake in the root and all should be updated.


Discovering open source WPF components – Orc.Snapshots

In the discovering open source WPF components series, I will look into useful open source components that can be used to create WPF apps. This weeks component is Orc.Snapshots.

Snapshots are like save games. They represent a set of data and/or values from a specific moment in time in an application. Using snapshots allows an application (and thus eventually the end-user) to store data (in memory, in a file or any in other persistence tech) which can later be retrieved. The advantage of using this library is that it will zip all the data into a single snapshot package

Whenever a snapshot is created, the SnapshotManager will:

  1. Create a zip memory stream
  2. For each provider, it will ask the provider to fill up a memory stream which is stored as a separate file
  3. Persist the snapshot memory stream to the required persistence store

Below is an animated gif of the example app that is available in the component repository:


The library makes it super convenient to add custom data to a snapshot. Just create a provider and register it in the manager and you’re done. This way you can even store (multiple) files (representing a specific moment in time) in a snapshot. Then the users can restore the snapshots whenever they want to.

Discovering open source WPF components – Orc.Wizard

In the discovering open source WPF components series, I will look into useful open source components that can be used to create WPF apps. This weeks component is Orc.Wizard.

A wizard is a great way to guide users through a process. Every wizard should behave the same, but there is no great out-of-the-box experience in WPF. The wizard included in this library has a few nice features:

  1. Automatic page management (with everything you expect from next / previous / finish, etc)
  2. Automatic (but optional) summary page that gathers all the information from each page to summarize what has been selected inside the wizard
  3. Optional pages that allow users to skip to a next page. It is also possible to enforce validation on a wizard page.
  4. Nice looking wizard header that is generated automatically based on the accent color

In summary, this library allows you to focus on the actual wizard content (the pages), not the wizard itself which is fully taken care of for you.


Creating wizard pages

A wizard page contains of three parts which are explained below.

Creating the wizard page model

The wizard model will hold all the information of the wizard page and return the summary (which is optional).

Creating the wizard page view model

The view model is responsible for the actual view logic. There can be a lot of stuff in here that is view-specific, as long as the results are stored into the model. This example uses the ViewModelToModel feature of Catel to automatically map the values between the view model and model. As you can see this example even contains validation, so users cannot continue to the next page when the validation does not succeed.

Creating the wizard page view

Below is the xaml view for the wizard page. Note that it’s just an ordinary Catel UserControl.

Creating the wizard

Once all the wizard pages have been created, it’s time to wrap it inside an actual wizard. Below is an example:

Using the wizard

Using the wizard can be done via the IWizardService. Below is an example on how to show a wizard: