One thing that has been recently announced by Microsoft is the availability of .NET Core 3. With it, you will be able to create WPF and Winforms apps with .NET Core. And one extra bonus is that both WPF and Winforms are being open sourced. You can check these in https://github.com/dotnet/wpf and https://github.com/dotnet/winforms.

The first step to create a .NET Core WPF program is to download the .NET Core 3.0 preview from https://dotnet.microsoft.com/download/dotnet-core/3.0. Once you have it installed, you can check that it was installed correctly by open a Command Line window and typing dotnet –info and seeing the installed version:

:

With that in place, you can change the current folder to a new folder and type

dotnet new wpf
dotnet run

This will create a new .NET Core 3.0 WPF project and will compile and run it. You should get something like this:

If you click on the Exit button, the application exits. If you take a look at the folder, you will see that it generated the WPF project file, App.xaml and App.xaml.cs, MainWindow.xaml and MainWindow.xaml.cs. The easiest way to edit these files is to use Visual Studio Code. Just open Visual Studio Code and go to menu File/Open Folder and open the folder for the project. There you will see the project files and will be able to run and debug your code:

A big difference can be noted in the csproj file. If you open it, you will see something like this:

<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">

  <PropertyGroup>
    <OutputType>WinExe</OutputType>
    <TargetFramework>netcoreapp3.0</TargetFramework>
    <UseWPF>true</UseWPF>
  </PropertyGroup>

</Project>

That’s very simple and there’s nothing else in the project file. There are some differences between this project and other types of .NET Core, like the console one:

  • The output type is WinExe, and not Exe, in the console app
  • The UseWPF clause is there and it’s set to true

Now, you can modify and run the project inside VS Code. Modify MainWindow.xaml and put this code in it:

<Window x:Class="DotNetCoreWPF.MainWindow" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
    xmlns:local="clr-namespace:DotNetCoreWPF" mc:Ignorable="d" Title="MainWindow" Height="450" Width="800">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="*"/>
            <RowDefinition Height="40"/>
        </Grid.RowDefinitions>
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition Height="40"/>
                <RowDefinition Height="40"/>
                <RowDefinition Height="40"/>
                <RowDefinition Height="40"/>
                <RowDefinition Height="40"/>
                <RowDefinition Height="40"/>
            </Grid.RowDefinitions>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="*"/>
                <ColumnDefinition Width="2*"/>
            </Grid.ColumnDefinitions>

            <TextBlock Text="Id"      Grid.Column="0" Grid.Row="0" Margin="5" VerticalAlignment="Center"/>
            <TextBlock Text="Name"    Grid.Column="0" Grid.Row="1" Margin="5" VerticalAlignment="Center"/>
            <TextBlock Text="Address" Grid.Column="0" Grid.Row="2" Margin="5" VerticalAlignment="Center"/>
            <TextBlock Text="City"    Grid.Column="0" Grid.Row="3" Margin="5" VerticalAlignment="Center"/>
            <TextBlock Text="Email"   Grid.Column="0" Grid.Row="4" Margin="5" VerticalAlignment="Center"/>
            <TextBlock Text="Phone"   Grid.Column="0" Grid.Row="5" Margin="5" VerticalAlignment="Center"/>
            <TextBox Grid.Column="1" Grid.Row="0" Margin="5"/>
            <TextBox Grid.Column="1" Grid.Row="1" Margin="5"/>
            <TextBox Grid.Column="1" Grid.Row="2" Margin="5"/>
            <TextBox Grid.Column="1" Grid.Row="3" Margin="5"/>
            <TextBox Grid.Column="1" Grid.Row="4" Margin="5"/>
            <TextBox Grid.Column="1" Grid.Row="5" Margin="5"/>
        </Grid>
        <Button Content="Submit" Width="65" Height="35" Grid.Row="1" HorizontalAlignment="Right" VerticalAlignment="Center" Margin="5,0"/>
    </Grid>
</Window>

Now, you can compile and run the app in VS Code with F5, and you will get something like this:

If you don’t want to use Visual Studio Code, you can edit your project in Visual Studio 2019. The first preview still doesn’t have a visual editor for the XAML file, but you can edit the XAML file in the editor, it will work fine.

Porting a WPF project to .NET Core

To port a WPF project to .NET Core, you should run the Portability Analyzer tool first, to see what problems you will find before porting it to .NET Core. This tool can be found here. You can download it and run on your current application, and check what APIs that are not portable.

I will be porting my DiskAnalisys project. This is a simple project, that uses the File.IO functions to enumerate the files in a folder and uses two NuGet packages to add a Folder Browser and Charts to WPF. The first step is to run the portability analysis on it. Run the PortabilityAnalizer app and point it to the folder where the executable is located:

When you click on the Analyze button, it will analyze the executable and generate an Excel spreadsheet with the results:

As you can see, all the code is compatible with .NET Core 3.0. So, let’s port it to .NET Core 3.0. I will show you three ways to do it: creating a new project, updating the .csproj file and using a tool.

Upgrading by Creating a new project

This way needs the most work, but it’s the simpler to fix. Just create a new folder and name it DiskAnalysisCorePrj. Then open a command line window and change the directory to the folder you’ve created. Then, type these commands:

dotnet new wpf
dotnet add package wpffolderbrowser
dotnet add package dotnetprojects.wpf.toolkit
dotnet run

These commands will create the WPF project, add the two required NuGet packages and run the default app. You may see a warning like this:

D:\Documentos\Artigos\Artigos\CSharp\WPFCore\DiskAnalysisCorePrj\DiskAnalysisCorePrj.csproj : warning NU1701: Package 'DotNetProjects.Wpf.Toolkit 5.0.43' was restored using '.NETFramework,Version=v4.6.1' instead of the project target framework '.NETCoreApp,Version=v3.0'. This package may not be fully compatible with your project.
D:\Documentos\Artigos\Artigos\CSharp\WPFCore\DiskAnalysisCorePrj\DiskAnalysisCorePrj.csproj : warning NU1701: Package 'WPFFolderBrowser 1.0.2' was restored using '.NETFramework,Version=v4.6.1' instead of the project target framework '.NETCoreApp,Version=v3.0'. This package may not be fully compatible with your project.
D:\Documentos\Artigos\Artigos\CSharp\WPFCore\DiskAnalysisCorePrj\DiskAnalysisCorePrj.csproj : warning NU1701: Package 'DotNetProjects.Wpf.Toolkit 5.0.43' was restored using '.NETFramework,Version=v4.6.1' instead of the project target framework '.NETCoreApp,Version=v3.0'. This package may not be fully compatible with your project.
D:\Documentos\Artigos\Artigos\CSharp\WPFCore\DiskAnalysisCorePrj\DiskAnalysisCorePrj.csproj : warning NU1701: Package 'WPFFolderBrowser 1.0.2' was restored using '.NETFramework,Version=v4.6.1' instead of the project target framework '.NETCoreApp,Version=v3.0'. This package may not be fully compatible with your project.

This means that the NuGet packages weren’t converted to .NET Core 3.0, but they are still usable (remember, the compatibility report showed 100% compatibility). Then, copy MainWindow.xaml and MainWindow.xaml.cs from the original folder to the new one. We don’t need to copy any other files, as no other files were changed. Then, type

dotnet run

and the program is executed:

Converting by Changing the .csproj file

This way is very simple, just changing the project file, but can be challenging, especially for very large projects. Just create a new folder and name it DiskAnalysisCoreCsp. Copy all files from the main folder of the original project (there’s no need of copying the Properties folder) and edit the .csproj file, changing it to:

<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
  <PropertyGroup>
    <OutputType>WinExe</OutputType>
    <TargetFramework>netcoreapp3.0</TargetFramework>
    <UseWPF>true</UseWPF>
  </PropertyGroup>
  <ItemGroup>
    <PackageReference Include="dotnetprojects.wpf.toolkit" Version="5.0.43" />
    <PackageReference Include="wpffolderbrowser" Version="1.0.2" />
  </ItemGroup>
</Project>

Then, type

dotnet run

and the program is executed.

Converting using a tool

The third way is to use a tool to convert the project. You must install the conversion extension created by Brian Lagunas, from here. Then, open your WPF project in Visual Studio, right-click in the project and select “Convert Project to .NET Core 3”.

That’s all. You now have a NET Core 3 app. If you did that in Visual Studio 2017, you won’t be able to open the project, you will need to compile it with dotnet run, or open it in Visual Studio code.

Conclusions

As you can see, although this is the first preview of WPF .NET Core, it has a lot of work done, and you will be able to port most of your WPF projects to .NET Core.