-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Description
Executive Summary
This proposal 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:
- No built-in dependency injection - forcing reliance on anti-patterns like static singletons
- Legacy configuration systems - XML-based settings files incompatible with cloud deployment
- Inconsistent application frameworks - VB and C# have different, outdated bootstrapping approaches
- Designer compatibility issues - making modern patterns difficult to adopt
- Limited Blazor Hybrid support - no clear path to integrate web technologies
- 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
Document Overview
This proposal is organized into the following sections:
- Modernization Goals - Detailed rationale for each feature area
- Core API Surface - Complete API specifications with proposed namespaces
- Namespace Strategy - Discussion of assembly and namespace organization
- Configuration Support - JSON-based configuration approach
- Bootstrapping Examples - C# and VB.NET samples
- Implementation Requirements - Runtime integration points
- Project & Solution Templates - Modern template ecosystem
- Migration Path - 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:
public interface IServiceProviderAssignable : IServiceProvider
{
/// <summary>
/// Sets the service provider for this component.
/// </summary>
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 Application Framework (with
ApplicationEvents.vb) - C# has Application Settings generators
- Both are inconsistent and limited
Proposal: Obsolete both and provide unified:
WinFormsApplicationBuilderfor both languages- Modern configuration via
appsettings.json - Consistent lifetime events
- Cross-language best practices
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 loggingAddWinFormsFileLogger(): Production file logging- Standard
ILogger<T>interface
8. Application Lifetime Service
Desktop applications need lifecycle hooks for:
- Startup initialization
- Graceful shutdown
- Resource cleanup
- State persistence
Solution: WinFormsApplicationLifetime providing:
ApplicationStartedeventApplicationStoppingeventApplicationStoppedevent- 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
WinFormsApplication Class
namespace Microsoft.Extensions.WinForms;
/// <summary>
/// Represents a configured Windows Forms application.
/// </summary>
public sealed class WinFormsApplication : IHost, IDisposable
{
/// <summary>
/// Gets the current running instance of the WinFormsApplication.
/// </summary>
public static WinFormsApplication? Current { get; }
/// <summary>
/// Gets the application's configured service provider.
/// </summary>
public IServiceProvider Services { get; }
/// <summary>
/// Creates a new WinFormsApplicationBuilder with pre-configured defaults.
/// </summary>
public static WinFormsApplicationBuilder CreateBuilder();
/// <summary>
/// Starts the host and runs the Windows Forms application with the configured startup form.
/// </summary>
public void Run();
/// <summary>
/// Starts the host and runs the Windows Forms application with the specified form type.
/// </summary>
public void Run<TForm>() where TForm : Form;
/// <summary>
/// Starts the host asynchronously.
/// </summary>
public Task StartAsync(CancellationToken cancellationToken = default);
/// <summary>
/// Stops the host asynchronously.
/// </summary>
public Task StopAsync(CancellationToken cancellationToken = default);
}WinFormsApplicationBuilder Class
namespace Microsoft.Extensions.WinForms;
/// <summary>
/// A builder for Windows Forms applications.
/// </summary>
public sealed class WinFormsApplicationBuilder : IHostApplicationBuilder
{
/// <summary>
/// Gets the collection of services for the application.
/// </summary>
public IServiceCollection Services { get; }
/// <summary>
/// Gets the application configuration.
/// </summary>
public ConfigurationManager Configuration { get; }
/// <summary>
/// Gets the logging builder for the application.
/// </summary>
public ILoggingBuilder Logging { get; }
/// <summary>
/// Gets the host environment for the application.
/// </summary>
public IHostEnvironment Environment { get; }
/// <summary>
/// Sets the startup form for the application using a form type.
/// </summary>
public WinFormsApplicationBuilder UseStartupForm<TForm>() where TForm : Form, new();
/// <summary>
/// Sets an existing form instance as the startup form.
/// </summary>
public WinFormsApplicationBuilder UseStartupForm(Form startupForm);
/// <summary>
/// Configures the high DPI mode for the application.
/// </summary>
public WinFormsApplicationBuilder UseHighDpiMode(HighDpiMode highDpiMode);
/// <summary>
/// Configures the color mode (Dark/Light/System) for the application.
/// </summary>
public WinFormsApplicationBuilder UseColorMode(SystemColorMode colorMode);
/// <summary>
/// Configures the default font for the application.
/// </summary>
public WinFormsApplicationBuilder UseDefaultFont(Font defaultFont);
/// <summary>
/// Configures whether to enable visual styles.
/// </summary>
public WinFormsApplicationBuilder UseVisualStyles(bool enable = true);
/// <summary>
/// Configures whether to use GDI+ text rendering (v2).
/// </summary>
public WinFormsApplicationBuilder UseTextRenderingV2(bool enable = true);
/// <summary>
/// Configures whether to allow WinForms settings from appsettings.json.
/// </summary>
public WinFormsApplicationBuilder AllowWinFormsJsonAppSettings(bool allowJson = true);
/// <summary>
/// Configures the application to use settings from the project file.
/// </summary>
public WinFormsApplicationBuilder UseProjectSettings();
/// <summary>
/// Adds WinForms-specific debug logging.
/// </summary>
public WinFormsApplicationBuilder UseWinFormsDebugLogger();
/// <summary>
/// Adds WinForms-specific release logging.
/// </summary>
public WinFormsApplicationBuilder UseWinFormsReleaseLogger();
/// <summary>
/// Builds the WinFormsApplication.
/// </summary>
public WinFormsApplication Build();
}WinFormsApplicationLifetime Class
namespace Microsoft.Extensions.WinForms;
/// <summary>
/// Represents the lifetime of a Windows Forms application.
/// </summary>
public sealed class WinFormsApplicationLifetime
{
/// <summary>
/// Occurs when the application has been fully started.
/// </summary>
public event EventHandler<EventArgs>? ApplicationStarted;
/// <summary>
/// Occurs when the application is stopping.
/// </summary>
public event EventHandler<EventArgs>? ApplicationStopping;
/// <summary>
/// Occurs when the application has completely stopped.
/// </summary>
public event EventHandler<EventArgs>? 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.WinFormsnamespace - Service integration in
System.ComponentModelnamespace
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
// 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:
// 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
- Alignment with .NET conventions: Use
Microsoft.Extensions.*pattern established by ASP.NET Core - Minimal surface area: Keep core types focused, allow extensions via standard patterns
- Clear ownership:
Microsoft.Extensions.WinFormsclearly indicates hosting infrastructure - Future-proof: Namespace structure allows for additional desktop UI framework support
Namespace: System.ComponentModel
IServiceProviderAssignable Interface
namespace System.ComponentModel;
/// <summary>
/// Represents a component that can receive a service provider after construction.
/// This enables dependency injection while maintaining Windows Forms Designer compatibility.
/// </summary>
public interface IServiceProviderAssignable : IServiceProvider
{
/// <summary>
/// Sets the service provider for this component.
/// </summary>
/// <param name="serviceProvider">The service provider to assign.</param>
/// <returns>The service provider for chaining.</returns>
IServiceProvider SetServiceProvider(object serviceProvider);
}Namespace: Microsoft.Extensions.DependencyInjection
Service Extension Methods
namespace Microsoft.Extensions.DependencyInjection;
public static class WinFormsServiceCollectionExtensions
{
/// <summary>
/// Adds the WinForms user settings service to the service collection.
/// </summary>
public static IServiceCollection AddWinFormsUserSettings(
this IServiceCollection services);
/// <summary>
/// Adds the WinForms exception handling service.
/// </summary>
public static IServiceCollection AddWinFormsExceptionHandling(
this IServiceCollection services);
/// <summary>
/// Adds the WinForms dialog service for showing dialogs.
/// </summary>
public static IServiceCollection AddWinFormsDialogs(
this IServiceCollection services);
/// <summary>
/// Gets a component from the service provider.
/// </summary>
public static TComponent? GetComponent<TComponent>(
this IServiceProvider serviceProvider);
/// <summary>
/// Gets a required component from the service provider.
/// </summary>
public static TComponent GetRequiredComponent<TComponent>(
this IServiceProvider serviceProvider);
}Namespace: Microsoft.Extensions.WinForms.Services
IUserSettingsService Interface
namespace Microsoft.Extensions.WinForms.Services;
/// <summary>
/// Provides a modern, JSON-based user settings service.
/// </summary>
public interface IUserSettingsService
{
/// <summary>
/// Gets a setting value with a default fallback.
/// </summary>
T GetSetting<T>(string key, T defaultValue);
/// <summary>
/// Saves a setting value.
/// </summary>
void SaveSetting<T>(string key, T value);
/// <summary>
/// Loads settings from disk.
/// </summary>
void Load();
/// <summary>
/// Saves settings to disk.
/// </summary>
void Save();
/// <summary>
/// Removes a setting.
/// </summary>
void Remove(string key);
}IWinFormsExceptionService Interface
namespace Microsoft.Extensions.WinForms.Services;
/// <summary>
/// Provides centralized exception handling for WinForms applications.
/// </summary>
public interface IWinFormsExceptionService
{
/// <summary>
/// Handles an exception that occurred in the application.
/// </summary>
void HandleException(Exception exception, bool canContinue = true);
/// <summary>
/// Configures global exception handlers.
/// </summary>
void ConfigureGlobalHandlers();
}Namespace: Microsoft.Extensions.Logging
Logging Extension Methods
namespace Microsoft.Extensions.Logging;
public static class WinFormsLoggingExtensions
{
/// <summary>
/// Adds a timestamped debug logger suitable for Windows Forms development.
/// </summary>
public static ILoggingBuilder AddDebugLogger(
this ILoggingBuilder builder,
string? timeStampFormat = null,
bool minuteSeparator = true);
/// <summary>
/// Adds a file logger for Windows Forms applications.
/// </summary>
public static ILoggingBuilder AddFileLogger(
this ILoggingBuilder builder,
string? applicationName = null,
string? logDirectory = null);
}Configuration Support
appsettings.json Structure
{
"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
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<MainForm>();
builder.Services.AddScoped<SettingsForm>();
// Configure logging
builder.Logging.AddDebugLogger();
builder.Logging.AddFileLogger();
// Configure WinForms-specific options
builder.UseStartupForm<MainForm>()
.UseHighDpiMode(HighDpiMode.PerMonitorV2)
.UseColorMode(SystemColorMode.System)
.UseTextRenderingV2()
.UseVisualStyles()
.AllowWinFormsJsonAppSettings();
// Build and run
WinFormsApplication app = builder.Build();
app.Run();
}
}C# Example - Advanced with Blazor Hybrid
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<FrmMain>();
builder.Services.AddScoped<ChatViewModel>();
// Logging
builder.Logging.AddDebugLogger();
// WinForms configuration
builder.UseStartupForm<FrmMain>()
.UseHighDpiMode(HighDpiMode.SystemAware)
.UseColorMode(SystemColorMode.System)
.UseTextRenderingV2()
.UseVisualStyles();
// Build and run
WinFormsApplication app = builder.Build();
app.Run();
}
}C# Example - Form with Dependency Injection
using System.ComponentModel;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.WinForms.Services;
namespace MyWinFormsApp;
/// <summary>
/// Main application form with dependency injection support.
/// </summary>
public partial class MainForm : Form, IServiceProviderAssignable
{
private readonly ILogger<MainForm> _logger;
private readonly IUserSettingsService _settings;
private IServiceProvider? _serviceProvider;
// Designer-compatible parameterless constructor
public MainForm()
{
InitializeComponent();
}
// Constructor for dependency injection
public MainForm(
ILogger<MainForm> 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
Imports Microsoft.Extensions.DependencyInjection
Imports Microsoft.Extensions.WinForms
Imports Microsoft.Extensions.Logging
Module Program
''' <summary>
''' The main entry point for the application.
''' </summary>
<STAThread()>
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 ModuleVB.NET Example - Form with Dependency Injection
Imports System.ComponentModel
Imports Microsoft.Extensions.Logging
Imports Microsoft.Extensions.WinForms.Services
''' <summary>
''' Main application form with dependency injection support.
''' </summary>
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 ClassProject 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:
- Lowering the barrier to entry - Developers can start with best practices immediately
- Showcasing capabilities - Templates demonstrate the full potential of the new infrastructure
- Accelerating development - Pre-configured solutions save hours of setup time
- Establishing patterns - Templates serve as reference implementations
- 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:
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<MainForm>();
// Configure logging
builder.Logging.AddDebugLogger();
// Configure WinForms
builder.UseStartupForm<MainForm>()
.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:
// In Program.cs
builder.Services.AddWindowsFormsBlazorWebView();
builder.Services.AddScoped<ChatViewModel>();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:
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:
- New Project Dialog - Filtered by "WinForms" or "Desktop"
- Getting Started - Featured in welcome screen
- 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
<Template>
<Name>WinForms App (.NET)</Name>
<Description>A modern Windows Forms application with dependency injection, logging, and configuration</Description>
<ProjectType>CSharp</ProjectType>
<ProjectSubType>Windows</ProjectSubType>
<SortOrder>1000</SortOrder>
<CreateNewFolder>true</CreateNewFolder>
<DefaultName>MyWinFormsApp</DefaultName>
<ProvideDefaultName>true</ProvideDefaultName>
<LocationField>Enabled</LocationField>
<EnableLocationBrowseButton>true</EnableLocationBrowseButton>
<CreateInPlace>true</CreateInPlace>
<Icon>WinFormsIcon.png</Icon>
<PreviewImage>WinFormsPreview.png</PreviewImage>
<Tags>
<Tag>WinForms</Tag>
<Tag>Desktop</Tag>
<Tag>DependencyInjection</Tag>
<Tag>Modern</Tag>
</Tags>
</Template>Benefits of Comprehensive Template Ecosystem
- Reduced Learning Curve - Developers don't need to configure DI, logging, etc. from scratch
- Best Practices by Default - Templates encode recommended patterns
- Faster Time to Market - Pre-wired solutions accelerate development
- Migration Support - Bridge templates provide clear migration paths
- 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)
WinFormsApplicationclassWinFormsApplicationBuilderclassWinFormsApplicationOptionsclassWinFormsApplicationLifetimeclass
2. Service Provider Integration
IServiceProviderAssignableinterface inSystem.ComponentModel- Updates to
Formbase class to support optional service provider injection - Updates to
Controlbase class to supportIServiceProviderAssignable - Designer code generation support for service provider assignment
3. Configuration Support
- Integration with
Microsoft.Extensions.Configuration appsettings.jsonsupport withWinFormssection- 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):
' 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 NamespaceAfter (WinFormsApplicationBuilder):
' Program.vb
Module Program
<STAThread()>
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 ModuleFrom C# Application.Run
Before:
static class Program
{
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetHighDpiMode(HighDpiMode.SystemAware);
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new MainForm());
}
}After:
static class Program
{
[STAThread]
static void Main()
{
var builder = WinFormsApplication.CreateBuilder();
builder.UseStartupForm<MainForm>()
.UseHighDpiMode(HighDpiMode.SystemAware)
.UseTextRenderingV2()
.UseVisualStyles();
var app = builder.Build();
app.Run();
}
}From Settings Files
Before (.settings file):
<Settings>
<Setting Name="WindowLocation" Type="System.Drawing.Point">
<Value>100, 100</Value>
</Setting>
</Settings>After (IUserSettingsService):
// 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:
- Providing first-class dependency injection support
- Enabling Blazor Hybrid scenarios
- Offering modern configuration and logging
- Unifying VB and C# application frameworks
- Maintaining full Designer compatibility
- 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.