Introduction
As of time of writing, Microsoft and the community are currently testing .NET Core 3.0. If you are reading this article after .NET Core 3.0's general availability, please skip the article. Otherwise, carry on.
In case the video frame doesn't show, please visit this link to watch the full demonstration of this article.
Windows Forms has been the pinnacle of maintaining business/enterprise desktop apps. Despite its archaic mechanics to develop desktop apps, Microsoft was able to recognize the strengths of the battle tested toolkit and decided to move it to the modern .NET Core platform (previously known as .NET Framework.)
So far, they managed to pull things together pretty well with the Windows Forms transition, but are missing some key components for early adopters and one of them happens to be the Windows Forms Designer; a tool built into Microsoft Visual Studio that aims to simplify user interface development. To acknowledge the Windows Forms Designer limitation in .NET Core 3.0 preview, try opening and designing any form/user control file (typically Form1.cs from a newly created project.) Hence, the result of the article's existence. This article will walk you through on how to overcome the limitation of .NET Core 3.0 preview's Windows Forms Designer without having to wait for its general availability.
Software Requirements
In order to follow along with the article, you must have the following components installed on your system:
- Microsoft Visual Studio 2019 - at least version 16.2.0
- .NET Core 3.0 preview 7 (as of the time of writing, preview 7 will be used)
Overcome the Limitation
Demonstrating the Problem
- Create a new Windows Forms App (.NET Core). If you can't see the entry on the left, use the convenient "Search for templates" search box and type in "Windows Forms App (.NET Core)".
- For this project, we will be naming it
DotNetCore.WinForms
, but you can name it anything you like, make sure to understand the concept and you'll be good to go. - Without making any change yet, try opening Form1.cs
file and you should be seeing something like this. Please don't be alarmed, this is normal behavior due to the fact that we are running the preview version of .NET Core 3.0. We will be solving this later on.
At this point, you start to get the feeling that you can't do any sort of user interface design under .NET Core 3.0 preview.
The Solution
To get around the limitation, we can use an approach where we can indirectly tap into the design of the .NET Core project by creating an additional Windows Forms project based on the fully functional .NET Framework. Please proceed till the end.
- Right click on the solution name and create a new solution folder with the name _TemporaryFixup.
- Under the _TemporaryFixup solution folder, create a new Windows Forms App (.NET Framework) project. If you can't see the entry on the left, use the convenient "Search for templates" search box and type in "Windows Forms App (.NET Framework)".
- For this project, we will be naming it DotNetFramework.WinForms, but you can name it anything you like.
- Delete the Form1.cs
file. - Right click on the
DotNetFramework.WinForms
project and click Properties. - Change the default namespace to match the same as the .NET Core project; in our case, we will set it to
DotNetCore.WinForms
(will be explained in a few) - Create a new form and name it to anything you like.
Now, let's modify Program.cs file in the DotNetFramework.WinForms
project with the following:
using System;
using System.IO;
using System.Linq;
namespace DotNetFramework.WinForms
{
static class Program
{
private static string SourceProjectDir =
@"C:\Users\ahmad\source\repos\DotNetCore.WinForms\DotNetFramework.WinForms";
private static string TargetProjectDir =
@"C:\Users\ahmad\source\repos\DotNetCore.WinForms\DotNetCore.WinForms";
[STAThread]
static void Main()
{
var directory = new DirectoryInfo(SourceProjectDir);
var srcFiles = directory.GetFiles("*.Designer.cs", SearchOption.AllDirectories);
foreach (var srcFile in srcFiles)
{
var relativeDirectory = $"{srcFile.DirectoryName.Substring
(SourceProjectDir.Length,
srcFile.DirectoryName.Length - SourceProjectDir.Length)}";
var designerFileName = $@"{relativeDirectory}\{srcFile.Name}";
var noDesignerFileName =
$@"{relativeDirectory}\{srcFile.Name.Replace(".Designer", "")}";
var srcDesignerFile = $"{SourceProjectDir}{designerFileName}";
var srcNoDesignerFile = $"{SourceProjectDir}{noDesignerFileName}";
var dstDesignerFile = $"{TargetProjectDir}{designerFileName}";
var dstNoDesignerFile = $"{TargetProjectDir}{noDesignerFileName}";
var dirs = relativeDirectory.Split('\\').ToList();
var currentDir = TargetProjectDir;
foreach (var dir in dirs)
{
currentDir = Path.Combine(currentDir, dir);
Directory.CreateDirectory(currentDir);
}
File.Copy(srcDesignerFile, dstDesignerFile, true);
if (!File.Exists(dstNoDesignerFile) && File.Exists(srcNoDesignerFile))
{
File.Copy(srcNoDesignerFile, dstNoDesignerFile, false);
}
}
}
}
}
Since we are focusing on developing our app on the .NET Core platform, we won't be needing to show any dialog from the .NET Framework counterpart. We'd rather *reflect* only the user interface design parts of the .NET Framework project to the .NET Core project. Which pretty much explains why we changed the default namespace to the .NET Framework project earlier, remember?
Make sure to modify SourceProjectDir
variable to hold your .NET Framework project directory and the TargetProjectDir
variable to hold the .NET Core project directory.
Next, we want to call out the .NET Framework executable everytime we want to build and run our .NET Core project. Before we move any further, build the entire solution first. Second, right click on the .NET Framework project and click on Properties, then choose Build Events from the tab on the left. On "Pre-build event command line" field, paste the following:
$(TargetPath)
Finally, you can start designing your user interface elements from the .NET Framework project and reflect your changes to the .NET Core project automagically by hitting Ctrl+Shift+B and then run!
Using the Code
The provided code above is essentially a reflector. It reflects only the form files of the .NET Framework project to the .NET Core project. You may modify the code with no limits to make it do what you intend it to do.
Points of Interest
The convenience of the Windows Forms Designer has been brought back. Whether you're planning to start fresh with Windows Forms under .NET Core or migrating your existing traditional .NET Framework based project, you can now easily proceed doing so without having to wait for .NET Core 3.0's general availability.
History
- Version 1.0 - Initial commit
- Version 1.0.1 - Added YouTube video link for demonstration