No, the title is not a mistake. You may be familiar with Xamarin Hot Reload or WPF Hot Reload and if you have used hot reload before, you know what a great time saver this is. What would you say, you can have Hot Reload for WinForms as well?
A friend of mine pointed me to a product called “LiveSharp” which has a tag line:
Hot Reload for Blazor, Xamarin Forms, UNO, and any other C# project!
Basic Concept
- LiveSharp comes with a “server component” which is installed quickly and easily as a dotnet global tool.
- A nuget package “LiveSharp” you simply add to the project you want to “enable” hot reload.
- Once the nuget package is installed, you’ll get a LiveSharp.dashboard.cs file in the project’s root directory. This file is used to setup and configure the hot reload for your project.
- As far as I understand, your WinForms project must run under NET 5 on order to make it work.
To make hot reload work with WinForms, you need to do some work, though. For my scenario it was surprisingly easy but depending on the project and complexity of the project, it could be challenging.
In my WinForms project Royal TS, I have a lot of configuration pages which are hosted in a property dialog. All those pages implement a certain interface and are derived from a specific class. Whenever I extend my app or add additional features, most of this work is done by changing or creating new property pages for my dialog host.

Working on DPI aware and theme aware applications, this can be a tedious task. As you change something on your page (layout related or change of functionality), you always have to re-start your application, open up the dialog, navigate to the page and verify the changes.
With LiveSharp, I’m now able to do this “live” and it’s a game changer!
Setup LiveSharp
Assuming you installed the server and added the nuget package to your project, open the LiveSharp.dashboard.cs file.
My property pages are all derived from the base class: PropertyPage.
[assembly: LiveSharpInject(typeof(PropertyPage))]
If you have a larger project, I recommend you target specific types for the LiveSharp injection to avoid performance issues. Note that you can have multiple lines of the above to target multiple different types.
My LiveSharpDashboard class looks like this:
namespace LiveSharp
{
class LiveSharpDashboard : ILiveSharpDashboard
{
PropertyPage _propertyPage;
// This method will be run during the start of your application and every time you update it
public void Configure(ILiveSharpRuntime app)
{
app.OnMethodCallIntercepted(typeof(PropertyPage), (methodIdentifier, instance, args) =>
{
if (instance is PropertyPage page)
_propertyPage = page;
});
app.OnCodeUpdateReceived(methods =>
{
_propertyPage?.Host?.HotReload();
});
}
public void Run(ILiveSharpRuntime app)
{
}
}
}
In the Configure method we setup two “hooks” to make all this work:
With OnMethodCallIntercepted we get the an instance of the object from type PropertyPage anytime a method on that type has been called. We keep a reference to that instance in a member variable _propertyPage.
With OnCodeUpdateReceived we have the chance to call a method to “reload” what we need. This is a custom method you need to implement in your project to replace objects or sync properties. In my case I simply added a method HotReload() to my dialog host. Since each property page has a reference to the host, it’s easy for me to call the method.
Implement Hot Reload in your App
Let’s take a look at the HotReload() method:
public void HotReload()
{
this.InvokeIfRequired(() =>
{
var activePage = _activePage;
PanelControlPages.Controls.Remove(activePage);
ActivatePage(_activePageId);
activePage.Dispose();
});
}
As you can see, the code is quite simple. Here’s what’s happening:
- InvokeIfRequired is a little helper extension method which ensures the code is executed on the UI thread. When the method is called from LiveSharp, it is most likely not the UI thread!
- The member _activePage holds an instance of the currently visible/active page (PropertyPage)
- The member _activePageId is the id of the page.
- The method ActivatePage(pageId) ensures that either an existing page with the provided id is shown or created and shown in case it doesn’t exist yet. Since I have removed the active page from the container at the line before, it will simply create a new instance.
- Lastly, I dispose the “old” page.
Conclusion
With the rise of XAML based UI frameworks with MVVM, hot reload, good DPI story, etc., WinForms started to feel clumsy. WinForms is old but WinForms is also mature. With WinForms brought to modern NET 5, we have a solid UI framework which still works great.
LiveSharp – for me at least – is a game changer. It isn’t free but pricing is really fair and if you primarily work on WinForms projects, this can save you lots of hours.
Co-Founder and CEO of Royal Apps GmbH and Windows lead developer for Royal TS, a multi platform, multi protocol remote management solution, for Windows, macOS and mobile supporting RDP, VNC, SSH, Telnet, and many more.
Long time Microsoft MVP (2010-2020) supporting communities on- and offline as well as speaking at user groups and conferences about DevOps and other software development topics.