OswaldTechnologies.Extensions.Hosting.WindowsFormsLifetime 1.1.0

dotnet add package OswaldTechnologies.Extensions.Hosting.WindowsFormsLifetime --version 1.1.0
NuGet\Install-Package OswaldTechnologies.Extensions.Hosting.WindowsFormsLifetime -Version 1.1.0
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="OswaldTechnologies.Extensions.Hosting.WindowsFormsLifetime" Version="1.1.0" />
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add OswaldTechnologies.Extensions.Hosting.WindowsFormsLifetime --version 1.1.0
#r "nuget: OswaldTechnologies.Extensions.Hosting.WindowsFormsLifetime, 1.1.0"
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
// Install OswaldTechnologies.Extensions.Hosting.WindowsFormsLifetime as a Cake Addin
#addin nuget:?package=OswaldTechnologies.Extensions.Hosting.WindowsFormsLifetime&version=1.1.0

// Install OswaldTechnologies.Extensions.Hosting.WindowsFormsLifetime as a Cake Tool
#tool nuget:?package=OswaldTechnologies.Extensions.Hosting.WindowsFormsLifetime&version=1.1.0

WindowsFormsLifetime

Build Status Nuget Nuget

A Windows Forms hosting extension for the .NET Generic Host. This library enables you to configure the generic host to use the lifetime of Windows Forms. When configured, the generic host will start an IHostedService that runs Windows Forms in a separate UI specific thread.

  • The Generic Host will use Windows Forms as it's lifetime (when the main form closes, the host shuts down)
  • All the benefits of .NET and the Generic Host, dependency injection, configuration, logging...
  • Easier multi-threading in Windows Forms

Quick Start

Install the OswaldTechnologies.Extensions.Hosting.WindowsFormsLifetime package from NuGet.

Using Powershell

Install-Package OswaldTechnologies.Extensions.Hosting.WindowsFormsLifetime

Using the .NET CLI

dotnet add package OswaldTechnologies.Extensions.Hosting.WindowsFormsLifetime

Create a new Windows Forms App.

Replace the contents of Program.cs with the following.

using Microsoft.Extensions.Hosting;
using WinFormsApp1;
using WindowsFormsLifetime;

var builder = Host.CreateApplicationBuilder(args);
builder.UseWindowsFormsLifetime<Form1>();

var app = builder.Build();
app.Run();

Run the app!

Your Windows Forms app is now running with the Generic Host!

Passing options

You can further configure the Windows Forms lifetime by passing Action<WindowsFormsLifeTimeOptions>. For example, with the default options:

builder.UseWindowsFormsLifetime<Form1>(options =>
{
    options.HighDpiMode = HighDpiMode.SystemAware;
    options.EnableVisualStyles = true;
    options.CompatibleTextRenderingDefault = false;
    options.SuppressStatusMessages = false;
    options.EnableConsoleShutdown = true;
});

EnableConsoleShutdown Allows the use of Ctrl+C to shutdown the host while the console is being used.

Instantiating and Showing Forms

Add more forms to the DI container.

var builder = Host.CreateApplicationBuilder(args);
builder.UseWindowsFormsLifetime<Form1>();
builder.Services.AddTransient<Form2>();
var app = builder.Build();
app.Run();

To get a form, use the IFormProvider. The form provider fetches an instance of the form from the DI container on the GUI thread. IFormProvider has the method, GetFormAsync<T>, used to fetch a form instance.

In this example, we inject IFormProvider into the main form, and use that to instantiate a new instance of Form2, then show the form.

public partial class Form1 : Form
{
    private readonly ILogger<Form1> _logger;
    private readonly IFormProvider _formProvider;

    public Form1(ILogger<Form1> logger, IFormProvider formProvider)
    {
        InitializeComponent();
        _logger = logger;
        _formProvider = formProvider;
    }

    private async void button1_Click(object sender, EventArgs e)
    {
        _logger.LogInformation("Show Form2");
        var form = await _formProvider.GetFormAsync<Form2>();
        form.Show();
    }
}

Invoking on the GUI thread

Sometimes you need to invoke an action on the GUI thread. Say you want to spawn a form from a background service. Use the IGuiContext to invoke actions on the GUI thread.

In this example, a form is fetched and shown, in an action that is invoked on the GUI thread. Then a second form is shown. This example shows how the GUI does not lock up during this process.

public class HostedService1 : BackgroundService
{
    private readonly ILogger _logger;
    private readonly IFormProvider _fp;
    private readonly IGuiContext _guiContext;

    public HostedService1(
        ILogger<HostedService1> logger,
        IFormProvider formProvider,
        IGuiContext guiContext)
    {
        _logger = logger;
        _fp = formProvider;
        _guiContext = guiContext;
    }

    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        int count = 0;
        while (!stoppingToken.IsCancellationRequested)
        {
            await Task.Delay(5000, stoppingToken);
            if (count < 5)
            {
                await _guiContext.InvokeAsync(async () =>
                {
                    var form = await _fp.GetFormAsync<Form2>();
                    form.Show();
                });
            }
            count++;
            _logger.LogInformation("HostedService1 Tick 1000ms");
        }
    }
}

Only use the Console while debugging

I like to configure my csproj so that the Console runs only while my configuration is set to Debug, and doesn't run when set to Release. Here is an example of how to do this. Setting the OutputType to Exe will run the console, while setting it to WinExe will not.

<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
  <OutputType>Exe</OutputType>
</PropertyGroup>

<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
  <OutputType>WinExe</OutputType>
</PropertyGroup>

Credits

The layout of the WindowsFormsLifetime class is based on .NET Core's ConsoleLifetime.

ExecutionContext vs SynchronizationContext

Implementing a SynchronizationContext.SendAsync method

Product Compatible and additional computed target framework versions.
.NET net6.0-windows7.0 is compatible.  net7.0-windows was computed.  net7.0-windows7.0 is compatible.  net8.0-windows was computed.  net8.0-windows7.0 is compatible. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (1)

Showing the top 1 NuGet packages that depend on OswaldTechnologies.Extensions.Hosting.WindowsFormsLifetime:

Package Downloads
WindowsFormsLifetime.Mvp

Model-View-Presenter extensions for WindowsFormsLifetime

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last updated
1.1.0 126 4/28/2024
1.0.2 2,398 11/26/2022
1.0.1 1,474 3/29/2022
1.0.0 697 12/6/2021
0.1.0 344 11/16/2021
0.0.5 267 11/11/2021
0.0.4 274 11/11/2021
0.0.3 1,400 2/12/2020
0.0.2 435 2/10/2020
0.0.1 499 2/9/2020