Notes on Migrating a WPF Application to .NET Core 3.0

Recently, I migrated a WPF application from .NET Framework 4.7.2 to .NET Core 3.0, which took me about two hours in total. The application consisted of four assemblies (one EXE, one UI class library, two other library assemblies).

A Google search for “migrate wpf to .net core 3” brings up enough helpful documentation to get started, so this post is mainly a reminder to myself what to look out for the next migration – which may be far enough in the future that I’ll have forgotten important bits by then.

How to get started

My starting point was the Microsoft article “Migrating WPF apps to .NET Core”. A lot of text, which makes it easy to get impatient and start just skimming for keywords. Tip: Do take your time.

In my case, I somehow missed an important detail concerning the AssemblyInfo.cs file at first.

AssemblyInfo.cs

When you migrate to .NET Core and use the new project file format, you have to decide what you want to do about the AssemblyInfo.cs file.

If you create a new .NET Core project, that file is autogenerated from information you can enter in the “Packages” section of the project properties in Visual Studio (the information is stored in the project file).

In the .NET Framework version of the UI class library, I used the attributes XmlnsDefinition and XmlnsPrefix to make the XAML in the EXE project prettier. That’s why I wanted to keep using an AssemblyInfo.cs file I could edit manually. For this, I had to add the following property:

<GenerateAssemblyInfo>false</GenerateAssemblyInfo>

PreBuild Step

I use a pre-build step in my UI library project (calling a tool called ResMerger), After the migration, macros like (ProjectDir) were no longer resolved. The migration document does not cover pre/post build events (at the time of this writing). But the article “Additions to the csproj format for .NET Core” does, in the section “Build events”.

PreBuild event in the old csproj file:

<PropertyGroup>
    <PreBuildEvent>"$(SolutionDir)tools\ResMerger.exe" "$(ProjectDir)Themes\\" $(ProjectName) "Generic.Source.xaml" "Generic.xaml"
    </PreBuildEvent>
</PropertyGroup>

And in the new csproj file:

<Target Name="PreBuild" BeforeTargets="PreBuildEvent">
    <Exec Command="&quot;$(SolutionDir)tools\ResMerger.exe&quot; &quot;$(ProjectDir)Themes\\&quot; $(ProjectName) Generic.Source.xaml Generic.xaml" />
</Target>

Note that the text of the PreBuild step is now stored in an XML attribute, and thus needs to be XML escaped. If you have a lot of PreBuild/PostBuild steps to deal with, it’s maybe a good idea to use the Visual Studio UI to copy and paste the texts before and after migrating the project file.

WPF Extended Toolkit

My application uses some controls from the Extended WPF Toolkit. An official version for .NET Core 3 has been announced but is not available yet. For my purposes I had success with a fork on https://github.com/dotnetprojects/WpfExtendedToolkit, your experience may be different.

Switching git branches

Switching back and forth between the git branches for the .NET framework and .NET Core versions inside Visual Studio results in error messages. To get rid of them, I do the typical troubleshooting move of exiting Visual Studio, deleting all bin and obj folders, restarting Visual Studio and rebuilding the solution. Fortunately, I don’t need to maintain the .NET framework in the future. The migration is done and I can move on.

Automating the project file conversion

For the next application, I’ll likely use the Visual Studio extension “Convert Project To .NET Core 3” by Brian Lagunas. I installed the extension and ran it on a test project – a quick look at the result was promising.

No Comments