dotnet / dotnet/winforms

[API Suggestion] WinForms Application Builder API Proposal

Open
#14,082 13 comments 14 reactions 2 assignees Claimed by @karajas View on GitHub
api-suggestion area-Infrastructure area-Templates design-discussion epic needs-area-label Review Issue
Dominant language
C#
Stars
4.9k
Forks
1.1k
Avg merge
20h 23m
Merged PRs (30d)
103

Description

## Executive Summary

This proposal (based on a couple of internal original suggestions, and - most importantly - the original proposal by https://github.com/dotnet/winforms/issues/14082 by @alex-oswald) outlines a comprehensive modernization of Windows Forms application development by introducing an **Application Builder Pattern** inspired by ASP.NET Core's proven infrastructure. The goal is to bring dependency injection, modern configuration, logging, and application lifetime management to WinForms applications while maintaining full Designer compatibility.

### Rationale

Windows Forms remains a critical technology for enterprise desktop applications, yet it lacks the modern development infrastructure that has made ASP.NET Core successful. Developers transitioning from .NET Framework to .NET, or building new desktop applications, face several challenges:

1. **No built-in dependency injection** - forcing reliance on anti-patterns like static singletons
2. **Legacy configuration systems** - XML-based settings files incompatible with cloud deployment
3. **Inconsistent application frameworks** - VB and C# have different, outdated bootstrapping approaches
4. **Designer compatibility issues** - making modern patterns difficult to adopt
5. **Limited Blazor Hybrid support** - no clear path to integrate web technologies
6. **Missing lifecycle management** - no standardized hooks for startup/shutdown operations

This proposal addresses these gaps by introducing a familiar, proven pattern that:
- Aligns WinForms with modern .NET practices used across all other workloads
- Maintains 100% Designer compatibility through innovative service provider assignment
- Enables seamless migration from .NET Framework while supporting greenfield development
- Provides a foundation for cloud-native desktop applications
- Unifies VB and C# development experiences

### Alternative/Original Feature suggestions

@alex-oswald https://github.com/dotnet/winforms/issues/11415

### Document Overview

This proposal is organized into the following sections:

1. **[Modernization Goals](#modernization-goals)** - Detailed rationale for each feature area
2. **[Core API Surface](#core-api-surface)** - Complete API specifications with proposed namespaces
3. **[Namespace Strategy](#namespace-strategy)** - Discussion of assembly and namespace organization
4. **[Configuration Support](#configuration-support)** - JSON-based configuration approach
5. **[Bootstrapping Examples](#bootstrapping-examples)** - C# and VB.NET samples
6. **[Implementation Requirements](#implementation-requirements-for-winforms-runtime)** - Runtime integration points
7. **[Project & Solution Templates](#project-and-solution-templates)** - Modern template ecosystem
8. **[Migration Path](#migration-path-from-legacy-approaches)** - Guidance for existing applications

---

## Modernization Goals

### 1. Dependency Injection for Migration and Modernization

Modern .NET applications rely heavily on dependency injection (DI) for:
- **Testability**: Components can be easily mocked and unit tested
- **Maintainability**: Loose coupling between components
- **Flexibility**: Easy to swap implementations without changing consuming code
- **Cloud-Native Patterns**: Aligns with microservices and modern architectural patterns

WinForms has lacked first-class DI support, forcing developers to:
- Use static singletons (anti-pattern)
- Manually wire dependencies
- Struggle with Designer compatibility

**Solution**: Introduce `WinFormsApplicationBuilder` that provides DI while maintaining Designer compatibility through `IServiceProviderAssignable`.

---

### 2. Blazor Hybrid Integration

Modern WinForms applications need to integrate web technologies:
- **Rich UI Components**: Leverage Blazor components in desktop apps
- **Code Reuse**: Share components between web and desktop
- **Modern Web APIs**: Utilize JavaScript libraries and frameworks

**Solution**: Seamless integration with `BlazorWebView` through service registration and DI.

---

### 3. Designer Compatibility via IServiceProviderAssignable

The WinForms Designer requires parameterless constructors, which conflicts with constructor injection.

**Solution**: Implement `IServiceProviderAssignable` interface that allows Designer-compatible controls to receive the service provider after construction:

```csharp
public interface IServiceProviderAssignable : IServiceProvider
{
///
/// Sets the service provider for this component.
///
IServiceProvider SetServiceProvider(object serviceProvider);
}
```

This enables:
- Designer continues to work with parameterless constructors
- Runtime injection through property/method call
- CodeDOM serialization compatibility

---

### 4. Modern Alternative to Legacy Settings Infrastructure

The current `.settings` file approach has limitations:
- XML-based, not JSON
- Limited type support
- No hierarchical configuration
- No environment-based overrides
- Incompatible with modern cloud deployment

**Solution**: `WinFormsUserSettingsService` providing:
- JSON-based storage
- Type-safe generic API
- Automatic serialization/deserialization
- Integration with `IConfiguration`

---

### 5. Extensible Builder Pattern with C# 14

C# 14 introduces enhanced extension method capabilities that enable:
- Fluent builder APIs
- Better type inference
- More expressive configuration
- Third-party extensibility

**Solution**: Builder pattern with extension methods for:
- Custom service registration
- Third-party library integration
- Domain-specific configuration

---

### 6. Unified VB and C# Application Framework

Currently:
- VB has a mature Application Framework (including `ApplicationEvents.vb`) with capabilities that C# applications cannot use through an equivalent shared abstraction.
- C# and VB use different bootstrapping and application-lifetime models.
- Some modern hosting, configuration, and DI patterns are difficult to adopt consistently across both languages.

**Proposal**: Introduce a shared application model that is equally approachable from VB and C#, while preserving the existing Visual Basic Application Framework. The shared model should:
- Use `WinFormsApplicationBuilder` consistently from both languages.
- Migrate the additional capabilities of the Visual Basic Application Framework into shared abstractions where practical, including startup/shutdown events, unhandled-exception handling, single-instance behavior and next-instance activation, command-line handling, splash-screen support, and application/network availability services.
- Provide modern configuration through `appsettings.json` and consistent lifetime events.
- Offer migration and compatibility adapters so existing VB applications are not broken or forced to rewrite.
- Let VB and C# benefit from the strongest features of both existing approaches.

The intent is **not** to remove the Visual Basic Application Framework. It is to provide an alternative shared foundation that VB and C# applications can adopt in the same way, with a deliberate compatibility and migration story.

---

### 7. Unified Logging and Services Experience

Developers need consistent logging across:
- Development (Debug output with timestamps)
- Production (File-based logs)
- Integration with Application Insights, Seq, etc.

**Solution**: Leverage `Microsoft.Extensions.Logging` with WinForms-specific providers:
- `AddTimeStampedDebug()`: Development logging
- `AddWinFormsFileLogger()`: Production file logging
- Standard `ILogger` interface

---

### 8. Application Lifetime Service

Desktop applications need lifecycle hooks for:
- Startup initialization
- Graceful shutdown
- Resource cleanup
- State persistence

**Solution**: `WinFormsApplicationLifetime` providing:
- `ApplicationStarted` event
- `ApplicationStopping` event
- `ApplicationStopped` event
- Integration with `IHostApplicationLifetime`

---

### 9. Additional Desktop-Specific Benefits from ASP.NET Infrastructure

By leveraging the existing `IHost` infrastructure, WinForms gains:

#### Configuration Management
- Hierarchical configuration (appsettings.json, environment variables, command line)
- Environment-specific settings (Development, Staging, Production)
- User secrets for sensitive data
- Hot reload support

#### Health Checks
- Application health monitoring
- Dependency health checks
- Integration with monitoring tools

#### Hosted Services
- Background task execution
- Scheduled jobs
- Long-running operations

#### Options Pattern
- Strongly-typed configuration
- Validation at startup
- Change notifications

#### Middleware Concept (WinForms Adaptation)
- Pre/post processing of form activation
- Global exception handling
- Logging interceptors
- Authorization checks

---

## Core API Surface

### Namespace: Microsoft.Extensions.WinForms

Suggestion: introduce a new assembly for Winforms:
`Microsoft.Extension.Hosting.WinForms.dll`

#### WinFormsApplication Class

```csharp
namespace Microsoft.Extensions.WinForms;

///
/// Represents a configured Windows Forms application.
///
public sealed class WinFormsApplication : IHost, IDisposable
{
///
/// Gets the current running instance of the WinFormsApplication.
///
public static WinFormsApplication? Current { get; }

///
/// Gets the application's configured service provider.
///
public IServiceProvider Services { get; }

///
/// Creates a new WinFormsApplicationBuilder with pre-configured defaults.
///
public static WinFormsApplicationBuilder CreateBuilder();

///
/// Starts the host and runs the Windows Forms application with the configured startup form.
///
public void Run();

///
/// Starts the host and runs the Windows Forms application with the specified form type.
///
public void Run() where TForm : Form;

///
/// Starts the host asynchronously.
///
public Task StartAsync(CancellationToken cancellationToken = default);

///
/// Stops the host asynchronously.
///
public Task StopAsync(CancellationToken cancellationToken = default);
}
```

---

#### WinFormsApplicationBuilder Class

```csharp
namespace Microsoft.Extensions.WinForms;

///
/// A builder for Windows Forms applications.
///
public sealed class WinFormsApplicationBuilder : IHostApplicationBuilder
{
///
/// Gets the collection of services for the application.
///
public IServiceCollection Services { get; }

///
/// Gets the application configuration.
///
public ConfigurationManager Configuration { get; }

///
/// Gets the logging builder for the application.
///
public ILoggingBuilder Logging { get; }

///
/// Gets the host environment for the application.
///
public IHostEnvironment Environment { get; }

///
/// Sets the startup form for the application using a form type.
///
public WinFormsApplicationBuilder UseStartupForm() where TForm : Form, new();

///
/// Sets an existing form instance as the startup form.
///
public WinFormsApplicationBuilder UseStartupForm(Form startupForm);

///
/// Configures the high DPI mode for the application.
///
public WinFormsApplicationBuilder UseHighDpiMode(HighDpiMode highDpiMode);

///
/// Configures the color mode (Dark/Light/System) for the application.
///
public WinFormsApplicationBuilder UseColorMode(SystemColorMode colorMode);

///
/// Configures the default font for the application.
///
public WinFormsApplicationBuilder UseDefaultFont(Font defaultFont);

///
/// Configures whether to enable visual styles.
///
public WinFormsApplicationBuilder UseVisualStyles(bool enable = true);

///
/// Configures whether to use GDI+ text rendering (v2).
///
public WinFormsApplicationBuilder UseTextRenderingV2(bool enable = true);

///
/// Configures whether to allow WinForms settings from appsettings.json.
///
public WinFormsApplicationBuilder AllowWinFormsJsonAppSettings(bool allowJson = true);

///
/// Configures the application to use settings from the project file.
///
public WinFormsApplicationBuilder UseProjectSettings();

///
/// Adds WinForms-specific debug logging.
///
public WinFormsApplicationBuilder UseWinFormsDebugLogger();

///
/// Adds WinForms-specific release logging.
///
public WinFormsApplicationBuilder UseWinFormsReleaseLogger();

///
/// Builds the WinFormsApplication.
///
public WinFormsApplication Build();
}
```

---

#### WinFormsApplicationLifetime Class

```csharp
namespace Microsoft.Extensions.WinForms;

///
/// Represents the lifetime of a Windows Forms application.
///
public sealed class WinFormsApplicationLifetime
{
///
/// Occurs when the application has been fully started.
///
public event EventHandler? ApplicationStarted;

///
/// Occurs when the application is stopping.
///
public event EventHandler? ApplicationStopping;

///
/// Occurs when the application has completely stopped.
///
public event EventHandler? ApplicationStopped;
}
```

---

## Namespace Strategy

### Assembly Organization

The proposed implementation can be organized in two potential approaches:

#### Option 1: Single Assembly Extension (Recommended for .NET 10+)

Add to existing `System.Windows.Forms.dll`:
- Core builder types in `Microsoft.Extensions.WinForms` namespace
- Service integration in `System.ComponentModel` namespace

**Benefits:**
- Single assembly reference
- Tight integration with existing WinForms infrastructure
- Natural discoverability

#### Option 2: Separate Assembly

Create new `Microsoft.Extensions.Hosting.WindowsForms.dll`:
- Contains all builder and hosting infrastructure
- References `System.Windows.Forms`
- Similar to `Microsoft.AspNetCore.Components.WebView.WindowsForms`

**Benefits:**
- Opt-in for applications that need it
- Easier to ship updates independently
- Clear separation of concerns

### Proposed Namespace Structure

```csharp
// Core hosting infrastructure
namespace Microsoft.Extensions.WinForms
{
public sealed class WinFormsApplication { }
public sealed class WinFormsApplicationBuilder { }
public sealed class WinFormsApplicationLifetime { }
internal sealed class WinFormsApplicationOptions { }
}

// Service provider integration for Designer compatibility
namespace System.ComponentModel
{
public interface IServiceProviderAssignable : IServiceProvider { }
}

// Extension methods for service registration
namespace Microsoft.Extensions.DependencyInjection
{
public static class WinFormsServiceCollectionExtensions
{
public static IServiceCollection AddWinFormsUserSettings(this IServiceCollection services);
public static IServiceCollection AddWinFormsExceptionHandling(this IServiceCollection services);
public static IServiceCollection AddWinFormsDialogs(this IServiceCollection services);
}
}

// Logging extensions
namespace Microsoft.Extensions.Logging
{
public static class WinFormsLoggingExtensions
{
public static ILoggingBuilder AddDebugLogger(this ILoggingBuilder builder);
public static ILoggingBuilder AddFileLogger(this ILoggingBuilder builder);
}
}

// Core services and interfaces
namespace Microsoft.Extensions.WinForms.Services
{
public interface IUserSettingsService { }
public interface IWinFormsExceptionService { }
public interface IWinFormsDialogService { }
}
```

### Third-Party Extensions

Third-party libraries can extend the builder pattern through standard extension methods:

```csharp
// Example: Blazor Hybrid support
namespace Microsoft.AspNetCore.Components.WebView.WindowsForms
{
public static class BlazorWebViewServiceCollectionExtensions
{
public static IServiceCollection AddWindowsFormsBlazorWebView(
this IServiceCollection services);
}
}

// Example: AI integration
namespace Microsoft.Extensions.AI.WinForms
{
public static class AIServiceCollectionExtensions
{
public static IServiceCollection AddAIChatClient(
this IServiceCollection services);
}
}
```

### Design Principles

1. **Alignment with .NET conventions**: Use `Microsoft.Extensions.*` pattern established by ASP.NET Core
2. **Minimal surface area**: Keep core types focused, allow extensions via standard patterns
3. **Clear ownership**: `Microsoft.Extensions.WinForms` clearly indicates hosting infrastructure
4. **Future-proof**: Namespace structure allows for additional desktop UI framework support

---

### Namespace: System.ComponentModel

#### IServiceProviderAssignable Interface

```csharp
namespace System.ComponentModel;

///
/// Represents a component that can receive a service provider after construction.
/// This enables dependency injection while maintaining Windows Forms Designer compatibility.
///
public interface IServiceProviderAssignable : IServiceProvider
{
///
/// Sets the service provider for this component.
///
/// The service provider to assign.
/// The service provider for chaining.
IServiceProvider SetServiceProvider(object serviceProvider);
}
```

---

### Namespace: Microsoft.Extensions.DependencyInjection

#### Service Extension Methods

```csharp
namespace Microsoft.Extensions.DependencyInjection;

public static class WinFormsServiceCollectionExtensions
{
///
/// Adds the WinForms user settings service to the service collection.
///
public static IServiceCollection AddWinFormsUserSettings(
this IServiceCollection services);

///
/// Adds the WinForms exception handling service.
///
public static IServiceCollection AddWinFormsExceptionHandling(
this IServiceCollection services);

///
/// Adds the WinForms dialog service for showing dialogs.
///
public static IServiceCollection AddWinFormsDialogs(
this IServiceCollection services);

///
/// Gets a component from the service provider.
///
public static TComponent? GetComponent(
this IServiceProvider serviceProvider);

///
/// Gets a required component from the service provider.
///
public static TComponent GetRequiredComponent(
this IServiceProvider serviceProvider);
}
```

---

### Namespace: Microsoft.Extensions.WinForms.Services

#### IUserSettingsService Interface

```csharp
namespace Microsoft.Extensions.WinForms.Services;

///
/// Provides a modern, JSON-based user settings service.
///
public interface IUserSettingsService
{
///
/// Gets a setting value with a default fallback.
///
T GetSetting(string key, T defaultValue);

///
/// Saves a setting value.
///
void SaveSetting(string key, T value);

///
/// Loads settings from disk.
///
void Load();

///
/// Saves settings to disk.
///
void Save();

///
/// Removes a setting.
///
void Remove(string key);
}
```

---

#### IWinFormsExceptionService Interface

```csharp
namespace Microsoft.Extensions.WinForms.Services;

///
/// Provides centralized exception handling for WinForms applications.
///
public interface IWinFormsExceptionService
{
///
/// Handles an exception that occurred in the application.
///
void HandleException(Exception exception, bool canContinue = true);

///
/// Configures global exception handlers.
///
void ConfigureGlobalHandlers();
}
```

---

### Namespace: Microsoft.Extensions.Logging

#### Logging Extension Methods

```csharp
namespace Microsoft.Extensions.Logging;

public static class WinFormsLoggingExtensions
{
///
/// Adds a timestamped debug logger suitable for Windows Forms development.
///
public static ILoggingBuilder AddDebugLogger(
this ILoggingBuilder builder,
string? timeStampFormat = null,
bool minuteSeparator = true);

///
/// Adds a file logger for Windows Forms applications.
///
public static ILoggingBuilder AddFileLogger(
this ILoggingBuilder builder,
string? applicationName = null,
string? logDirectory = null);
}
```

---

## Configuration Support

### appsettings.json Structure

```json
{
"WinForms": {
"HighDpiMode": "PerMonitorV2",
"ColorMode": "System",
"UseTextRenderingV2": true,
"UseVisualStyles": true,
"DefaultFont": {
"Family": "Segoe UI",
"Size": 9.0
}
},
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning"
}
},
"UserSettings": {
"StoragePath": "%APPDATA%/MyApp/settings.json"
}
}
```

---

## Bootstrapping Examples

### C# Example - Basic Application

```csharp
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.WinForms;
using Microsoft.Extensions.Logging;

namespace MyWinFormsApp;

internal static class Program
{
[STAThread]
static void Main()
{
// Create the application builder
WinFormsApplicationBuilder builder = WinFormsApplication.CreateBuilder();

// Configure services
builder.Services.AddWinFormsUserSettings();
builder.Services.AddWinFormsExceptionHandling();
builder.Services.AddWinFormsDialogs();

// Register application forms and components
builder.Services.AddScoped();
builder.Services.AddScoped();

// Configure logging
builder.Logging.AddDebugLogger();
builder.Logging.AddFileLogger();

// Configure WinForms-specific options
builder.UseStartupForm()
.UseHighDpiMode(HighDpiMode.PerMonitorV2)
.UseColorMode(SystemColorMode.System)
.UseTextRenderingV2()
.UseVisualStyles()
.AllowWinFormsJsonAppSettings();

// Build and run
WinFormsApplication app = builder.Build();
app.Run();
}
}
```

---

### C# Example - Advanced with Blazor Hybrid

```csharp
using Microsoft.AspNetCore.Components.WebView.WindowsForms;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.WinForms;
using Microsoft.Extensions.Logging;

namespace ChattyApp;

internal static class Program
{
[STAThread]
static void Main()
{
WinFormsApplicationBuilder builder = WinFormsApplication.CreateBuilder();

// Core services
builder.Services.AddWinFormsUserSettings();
builder.Services.AddWinFormsExceptionHandling();

// Blazor Hybrid support
builder.Services.AddWindowsFormsBlazorWebView();

// Application components
builder.Services.AddScoped();
builder.Services.AddScoped();

// Logging
builder.Logging.AddDebugLogger();

// WinForms configuration
builder.UseStartupForm()
.UseHighDpiMode(HighDpiMode.SystemAware)
.UseColorMode(SystemColorMode.System)
.UseTextRenderingV2()
.UseVisualStyles();

// Build and run
WinFormsApplication app = builder.Build();
app.Run();
}
}
```

---

### C# Example - Form with Dependency Injection

```csharp
using System.ComponentModel;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.WinForms.Services;

namespace MyWinFormsApp;

///
/// Main application form with dependency injection support.
///
public partial class MainForm : Form, IServiceProviderAssignable
{
private readonly ILogger _logger;
private readonly IUserSettingsService _settings;
private IServiceProvider? _serviceProvider;

// Designer-compatible parameterless constructor
public MainForm()
{
InitializeComponent();
}

// Constructor for dependency injection
public MainForm(
ILogger logger,
IUserSettingsService settings) : this()
{
_logger = logger;
_settings = settings;

_logger.LogInformation("MainForm initialized with DI");
}

// IServiceProviderAssignable implementation
public IServiceProvider SetServiceProvider(object serviceProvider)
{
_serviceProvider = (IServiceProvider)serviceProvider;
return _serviceProvider;
}

public object? GetService(Type serviceType)
=> _serviceProvider?.GetService(serviceType);

protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);

// Load window position from settings
if (_settings.GetSetting("WindowMaximized", false))
{
WindowState = FormWindowState.Maximized;
}
else
{
Location = _settings.GetSetting("WindowLocation", Location);
Size = _settings.GetSetting("WindowSize", Size);
}
}

protected override void OnFormClosing(FormClosingEventArgs e)
{
// Save window position
_settings.SaveSetting("WindowMaximized",
WindowState == FormWindowState.Maximized);

if (WindowState == FormWindowState.Normal)
{
_settings.SaveSetting("WindowLocation", Location);
_settings.SaveSetting("WindowSize", Size);
}

_settings.Save();

base.OnFormClosing(e);
}
}
```

---

### VB.NET Example - Basic Application

```vb
Imports Microsoft.Extensions.DependencyInjection
Imports Microsoft.Extensions.WinForms
Imports Microsoft.Extensions.Logging

Module Program
'''
''' The main entry point for the application.
'''

Sub Main()
' Create the application builder
Dim builder As WinFormsApplicationBuilder = _
WinFormsApplication.CreateBuilder()

' Configure services
builder.Services.AddWinFormsUserSettings()
builder.Services.AddWinFormsExceptionHandling()
builder.Services.AddWinFormsDialogs()

' Register application forms
builder.Services.AddScoped(Of MainForm)()
builder.Services.AddScoped(Of SettingsForm)()

' Configure logging
builder.Logging.AddDebugLogger()
builder.Logging.AddFileLogger()

' Configure WinForms-specific options
builder.UseStartupForm(Of MainForm)() _
.UseHighDpiMode(HighDpiMode.PerMonitorV2) _
.UseColorMode(SystemColorMode.System) _
.UseTextRenderingV2() _
.UseVisualStyles() _
.AllowWinFormsJsonAppSettings()

' Build and run
Dim app As WinFormsApplication = builder.Build()
app.Run()
End Sub
End Module
```

---

### VB.NET Example - Form with Dependency Injection

```vb
Imports System.ComponentModel
Imports Microsoft.Extensions.Logging
Imports Microsoft.Extensions.WinForms.Services

'''
''' Main application form with dependency injection support.
'''
Public Class MainForm
Inherits Form
Implements IServiceProviderAssignable

Private ReadOnly _logger As ILogger(Of MainForm)
Private ReadOnly _settings As IUserSettingsService
Private _serviceProvider As IServiceProvider

' Designer-compatible parameterless constructor
Public Sub New()
InitializeComponent()
End Sub

' Constructor for dependency injection
Public Sub New(logger As ILogger(Of MainForm),
settings As IUserSettingsService)
Me.New()
_logger = logger
_settings = settings

_logger.LogInformation("MainForm initialized with DI")
End Sub

' IServiceProviderAssignable implementation
Public Function SetServiceProvider(serviceProvider As Object) _
As IServiceProvider _
Implements IServiceProviderAssignable.SetServiceProvider

_serviceProvider = DirectCast(serviceProvider, IServiceProvider)
Return _serviceProvider
End Function

Public Function GetService(serviceType As Type) As Object _
Implements IServiceProvider.GetService

Return _serviceProvider?.GetService(serviceType)
End Function

Protected Overrides Sub OnLoad(e As EventArgs)
MyBase.OnLoad(e)

' Load window position from settings
If _settings.GetSetting("WindowMaximized", False) Then
WindowState = FormWindowState.Maximized
Else
Location = _settings.GetSetting("WindowLocation", Location)
Size = _settings.GetSetting("WindowSize", Size)
End If
End Sub

Protected Overrides Sub OnFormClosing(e As FormClosingEventArgs)
' Save window position
_settings.SaveSetting("WindowMaximized",
WindowState = FormWindowState.Maximized)

If WindowState = FormWindowState.Normal Then
_settings.SaveSetting("WindowLocation", Location)
_settings.SaveSetting("WindowSize", Size)
End If

_settings.Save()

MyBase.OnFormClosing(e)
End Sub
End Class
```

---

## Project and Solution Templates

### Importance of Modern Templates

The success of the WinFormsApplicationBuilder pattern depends heavily on **discoverability** and **ease of adoption**. Modern templates are essential for:

1. **Lowering the barrier to entry** - Developers can start with best practices immediately
2. **Showcasing capabilities** - Templates demonstrate the full potential of the new infrastructure
3. **Accelerating development** - Pre-configured solutions save hours of setup time
4. **Establishing patterns** - Templates serve as reference implementations
5. **Supporting migrations** - Multi-process templates help bridge .NET Framework to .NET transitions

### Proposed Template Ecosystem

#### Project Templates

| Template Name | Description | Key Features |
|--------------|-------------|--------------|
| **WinForms App (.NET)** | Basic application with DI | Builder pattern, logging, settings service |
| **WinForms App with Blazor** | Hybrid web/desktop app | BlazorWebView integration, shared Razor components |
| **WinForms System Tray App** | Background app with tray icon | NotifyIcon setup, context menus, minimize-to-tray |
| **WinForms Windows Service** | Long-running service | BackgroundService integration, service lifecycle |
| **WinForms MVVM App** | MVVM architecture | CommunityToolkit.Mvvm, data binding, commands |

#### Solution Templates

| Template Name | Description | Architecture |
|--------------|-------------|-------------|
| **WinForms Enterprise App** | Full-stack application | Frontend → ViewModels → Services → Data (EF Core) |
| **WinForms with Azure Backend** | Cloud-connected app | Desktop client → Azure Functions → Cosmos DB/SQL |
| **Blazor Hybrid Solution** | Shared UI components | WinForms + Blazor WebAssembly + Shared Razor Class Library |
| **Migration Bridge Solution** | .NET Framework coexistence | .NET 10 frontend ↔ IPC ↔ .NET Framework backend |
| **Multi-Tier WinForms App** | Layered architecture | Presentation → Business Logic → Data Access → Database |

### Template Details

#### 1. WinForms App (.NET) - Basic Template

**Project Structure:**
```
MyWinFormsApp/
├── Program.cs // Application builder setup
├── appsettings.json // Configuration
├── MainForm.cs // Main form with DI
├── MainForm.Designer.cs
├── Services/
│ └── IMyService.cs // Example service interface
└── Properties/
└── launchSettings.json // Development settings
```

**Program.cs:**
```csharp
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.WinForms;
using Microsoft.Extensions.Logging;

var builder = WinFormsApplication.CreateBuilder();

// Configure services
builder.Services.AddWinFormsUserSettings();
builder.Services.AddWinFormsExceptionHandling();
builder.Services.AddScoped();

// Configure logging
builder.Logging.AddDebugLogger();

// Configure WinForms
builder.UseStartupForm()
.UseHighDpiMode(HighDpiMode.PerMonitorV2)
.UseColorMode(SystemColorMode.System);

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

---

#### 2. WinForms with Blazor Template

**Project Structure:**
```
MyBlazorHybridApp/
├── Program.cs
├── MainForm.cs // Hosts BlazorWebView
├── Components/
│ ├── App.razor // Blazor root component
│ ├── Routes.razor
│ └── Pages/
│ ├── Index.razor
│ └── Counter.razor
├── wwwroot/
│ ├── css/
│ └── index.html
└── appsettings.json
```

**Key Configuration:**
```csharp
// In Program.cs
builder.Services.AddWindowsFormsBlazorWebView();
builder.Services.AddScoped();
```

---

#### 3. Migration Bridge Solution Template

**Solution Structure:**
```
MyMigrationSolution/
├── MyApp.Modern/ // .NET 10 WinForms
│ ├── Program.cs
│ ├── MainForm.cs
│ └── Services/
│ └── LegacyBridge.cs // IPC to legacy code
├── MyApp.Legacy/ // .NET Framework 4.8
│ ├── LegacyService.cs // Existing business logic
│ └── IPC/
│ └── NamedPipeServer.cs
└── MyApp.Shared/ // .NET Standard 2.0
└── Contracts/
└── ILegacyService.cs
```

**Migration Strategy:**
- Modern UI in .NET 10 with full DI and builder pattern
- Legacy business logic remains in .NET Framework
- Communication via named pipes or gRPC
- Gradual migration of business logic to .NET

---

#### 4. WinForms Enterprise App Solution Template

**Solution Structure:**
```
MyEnterpriseApp/
├── MyApp.Desktop/ // WinForms frontend
│ ├── Program.cs
│ ├── Views/
│ └── ViewModels/
├── MyApp.Core/ // Business logic
│ ├── Services/
│ └── Models/
├── MyApp.Data/ // Data access
│ ├── DbContext.cs
│ └── Repositories/
└── MyApp.Tests/ // Unit tests
├── ViewModelTests/
└── ServiceTests/
```

**Dependency Flow:**
```
Desktop → Core → Data
↓ ↓
└─────→ Tests
```

---

#### 5. WinForms with Azure Backend Template

**Solution Structure:**
```
MyCloudApp/
├── MyApp.Desktop/ // WinForms client
│ ├── Program.cs
│ ├── MainForm.cs
│ └── Services/
│ └── AzureApiClient.cs
├── MyApp.Functions/ // Azure Functions
│ ├── CustomerApi.cs
│ └── host.json
├── MyApp.Shared/ // DTOs and contracts
│ └── Models/
└── deployment/
├── bicep/ // Infrastructure as Code
└── pipelines/ // CI/CD
```

**Features:**
- REST API client with HttpClient factory
- Azure AD authentication
- Application Insights integration
- Offline-first data synchronization
- Deployment scripts for Azure

---

#### 6. System Tray Application Template

**Key Components:**
```csharp
public class TrayApplicationContext : ApplicationContext
{
private readonly NotifyIcon _notifyIcon;
private readonly IServiceProvider _services;

public TrayApplicationContext(IServiceProvider services)
{
_services = services;
_notifyIcon = new NotifyIcon
{
Icon = Resources.AppIcon,
ContextMenuStrip = CreateContextMenu(),
Visible = true
};
}

private ContextMenuStrip CreateContextMenu()
{
var menu = new ContextMenuStrip();
menu.Items.Add("Open", null, OnOpen);
menu.Items.Add("Settings", null, OnSettings);
menu.Items.Add("Exit", null, OnExit);
return menu;
}
}
```

---

### Template Discovery and Documentation

#### Visual Studio Integration

Templates should appear in:
1. **New Project Dialog** - Filtered by "WinForms" or "Desktop"
2. **Getting Started** - Featured in welcome screen
3. **Template Search** - Tagged with relevant keywords (WinForms, Desktop, Blazor, Azure, MVVM)

#### Online Documentation

Each template should include:
- **README.md** - Project overview and quick start
- **Architecture.md** - Design decisions and structure explanation
- **Migration-Guide.md** (for bridge templates) - Step-by-step migration process
- **Deployment.md** - How to build and deploy
- **Code comments** - Inline explanations of key patterns

#### Template Metadata

```xml

WinForms App (.NET)
A modern Windows Forms application with dependency injection, logging, and configuration
CSharp
Windows
1000
true
MyWinFormsApp
true
Enabled
true
true
WinFormsIcon.png
WinFormsPreview.png

WinForms
Desktop
DependencyInjection
Modern

```

---

### Benefits of Comprehensive Template Ecosystem

1. **Reduced Learning Curve** - Developers don't need to configure DI, logging, etc. from scratch
2. **Best Practices by Default** - Templates encode recommended patterns
3. **Faster Time to Market** - Pre-wired solutions accelerate development
4. **Migration Support** - Bridge templates provide clear migration paths
5. **Ecosystem Growth** - Templates encourage adoption of modern WinForms development

---

## Implementation Requirements for WinForms Runtime

To fully support this API surface in the .NET runtime, the following components need to be added to `System.Windows.Forms`:

### 1. Core Builder Types (Namespace: Microsoft.Extensions.WinForms)

- `WinFormsApplication` class
- `WinFormsApplicationBuilder` class
- `WinFormsApplicationOptions` class
- `WinFormsApplicationLifetime` class

### 2. Service Provider Integration

- `IServiceProviderAssignable` interface in `System.ComponentModel`
- Updates to `Form` base class to support optional service provider injection
- Updates to `Control` base class to support `IServiceProviderAssignable`
- Designer code generation support for service provider assignment

### 3. Configuration Support

- Integration with `Microsoft.Extensions.Configuration`
- `appsettings.json` support with `WinForms` section
- Environment-specific configuration (Development/Production)
- User secrets support for development

### 4. Logging Integration

- Integration with `Microsoft.Extensions.Logging`
- Default providers for Debug output and file logging
- Structured logging support

### 5. Lifetime Management

- Integration with `IHostApplicationLifetime`
- Application startup/shutdown event hooks
- Graceful shutdown support

### 6. Settings Service

- Modern replacement for `ApplicationSettings`
- JSON-based storage
- Type-safe generic API
- Automatic serialization

---

## Migration Path from Legacy Approaches

### From VB Application Framework

**Before (VB Application Framework):**
```vb
' ApplicationEvents.vb
Namespace My
Partial Friend Class MyApplication
Private Sub MyApplication_Startup(sender As Object,
e As StartupEventArgs) _
Handles Me.Startup
' Initialization code
End Sub
End Class
End Namespace
```

**After (WinFormsApplicationBuilder):**
```vb
' Program.vb
Module Program

Sub Main()
Dim builder = WinFormsApplication.CreateBuilder()

' Configure services and startup
builder.Services.AddSingleton(Of IMyService, MyService)()
builder.UseStartupForm(Of MainForm)()

Dim app = builder.Build()

' Subscribe to lifetime events
Dim lifetime = app.Services.GetService(Of WinFormsApplicationLifetime)()
AddHandler lifetime.ApplicationStarted, AddressOf OnStartup

app.Run()
End Sub

Private Sub OnStartup(sender As Object, e As EventArgs)
' Initialization code
End Sub
End Module
```

### From C# Application.Run

**Before:**
```csharp
static class Program
{
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetHighDpiMode(HighDpiMode.SystemAware);
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new MainForm());
}
}
```

**After:**
```csharp
static class Program
{
[STAThread]
static void Main()
{
var builder = WinFormsApplication.CreateBuilder();

builder.UseStartupForm()
.UseHighDpiMode(HighDpiMode.SystemAware)
.UseTextRenderingV2()
.UseVisualStyles();

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

### From Settings Files

**Before (.settings file):**
```xml


100, 100

```

**After (IUserSettingsService):**
```csharp
// Save
_settings.SaveSetting("WindowLocation", this.Location);
_settings.Save();

// Load
Location = _settings.GetSetting("WindowLocation", new Point(100, 100));
```

---

## Benefits Summary

### For Developers
- **Modern Patterns**: DI, logging, configuration aligned with ASP.NET Core
- **Better Testing**: Easy to mock and unit test
- **Cloud-Ready**: Supports cloud deployment patterns
- **Blazor Integration**: Seamless hybrid web/desktop apps
- **Type Safety**: Strongly-typed configuration and settings

### For the Ecosystem
- **Consistency**: Same patterns across all .NET workloads
- **Extensibility**: Third-party libraries can provide builder extensions
- **Maintainability**: Clear separation of concerns
- **Documentation**: Familiar patterns from web development

### For Migration
- **Incremental**: Can adopt features gradually
- **Backward Compatible**: Doesn't break existing code
- **Designer Compatible**: Works with Visual Studio Designer
- **VB and C# Unified**: Same API surface for both languages

---

## Conclusion

The `WinFormsApplicationBuilder` pattern brings Windows Forms development into the modern .NET era by:

1. Providing first-class dependency injection support
2. Enabling Blazor Hybrid scenarios
3. Offering modern configuration and logging
4. Unifying VB and C# application frameworks
5. Maintaining full Designer compatibility
6. Paving the way for cloud-native desktop applications

This proposal leverages existing, proven infrastructure from ASP.NET Core while respecting the unique requirements of desktop application development. The result is a modernized development experience that makes WinForms competitive with contemporary UI frameworks while preserving its strengths: Designer support, performance, and Windows integration.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.