You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Currently, enabling high DPI awareness (PerMonitorV2) in WinForms applications requires manual setup in Program.cs using Application.SetHighDpiMode. This approach has several limitations:
Developers often forget to set it or set it incorrectly.
It does not handle runtime DPI changes when moving between monitors with different scaling.
Custom controls that use SkiaSharp or direct GDI+ drawing need additional code to rescale properly.
This proposal introduces a zero-configuration, plug-and-play solution that automatically enables PerMonitorV2 DPI awareness as soon as the assembly loads (via ModuleInitializer), and provides a clean pattern for handling runtime DPI changes in custom controls. The solution works across .NET Framework 4.8 to .NET 8+.
Since it worked for me im sending you this (im using a translator sorry if some things sounds weird that would be the translator XD im learning english)anyways hope this helps you :')
API Proposal
#nullable enable
usingSystem.Diagnostics;usingSystem.Runtime.InteropServices;// 🔥 FIX DE COMPATIBILIDAD MULTI-TARGET (Resuelve la advertencia CS0436)// Solo inyectamos este atributo si el framework es más viejo que .NET 5 (ej. .NET 4.8). // .NET 8 ya lo trae de fábrica, así que lo ignora mágicamente.
#if !NET5_0_OR_GREATERnamespaceSystem.Runtime.CompilerServices{[AttributeUsage(AttributeTargets.Method,Inherited=false)]internalsealedclassModuleInitializerAttribute:Attribute{}}
#endif
namespaceFluentWinForms.Core{/// <summary>/// El motor de arranque fantasma. /// Se auto-ejecuta cuando la DLL se carga en memoria (Plug & Play real)./// </summary>publicstaticclassFluentEngine{[DllImport("user32.dll",SetLastError=true)]privatestaticexternboolSetProcessDpiAwarenessContext(intdpiFlag);[DllImport("user32.dll")]privatestaticexternboolSetProcessDPIAware();privatestaticbool_isInitialized=false;// 🔥 ESTA ETIQUETA HACE QUE SE EJECUTE SOLO AL INSTALAR EL NUGET[System.Runtime.CompilerServices.ModuleInitializer]publicstaticvoidInitialize(){if(_isInitialized)return;ForceHighDpiAwareness();// Iniciamos el tracker del Tema de Windows automáticamente en segundo plano// AppTheme.SyncWithSystemTheme(); // (only for my engine, not needed for DPI)_isInitialized=true;Trace.WriteLine("[FluentWinForms] Motor auto-inicializado en Alto Rendimiento (Plug & Play).");}privatestaticvoidForceHighDpiAwareness(){try{// Intentamos activar "PerMonitorV2" (Soporte Retina para Windows 10/11)// -4 equivale a DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2if(!SetProcessDpiAwarenessContext(-4)){// Fallback para Windows antiguos (Windows 7 / 8)SetProcessDPIAware();}}catch{// Silenciamos si hay restricciones extremas en el SO del usuario}}}}
Step 3: Native WinForms controls work automatically
Standard controls (Button, TextBox, DataGridView, etc.) scale automatically because the process is DPI-aware. No additional code is required.
Alternative Designs
Manual approach (current status quo):
Calling Application.SetHighDpiMode(HighDpiMode.PerMonitorV2) in Program.cs.
Downside: No runtime DPI change handling; easy to forget; requires extra code.
app.config manifest approach:
Declaring DPI awareness in the application manifest.
Downside: Not flexible; doesn't handle runtime changes; requires manifest editing.
Per-control scaling using DpiChanged event:
Subscribing to the DpiChanged event on each control.
Downside: Verbose; easy to miss controls; high maintenance.
The proposed solution combines the best of both worlds: automatic initialization at the process level + a clean, reusable pattern for custom control authors.
Risks
Breaking changes: None. The solution is additive and opt-in via library reference.
Performance: The ModuleInitializer runs once at assembly load (negligible overhead). The OnDpiChangedAfterParent handler runs only when the control's DPI changes (rare event). The S() helper is a simple multiplication.
Compatibility:
Works on Windows 10/11 with PerMonitorV2.
Falls back to SetProcessDPIAware on older Windows (7/8).
Silently fails if the OS doesn't support DPI awareness.
The conditional ModuleInitializerAttribute ensures compilation on .NET Framework 4.8 without errors.
Potential issues:
Some very old applications (Windows 7 without updates) may not support SetProcessDpiAwarenessContext. The try-catch handles this gracefully with a fallback.
Testing: Verified on .NET Framework 4.8, and .NET 8, with both standard WinForms controls and SkiaSharp-based custom rendering.
Will this feature affect UI controls?
Yes, but positively: all controls (both standard and custom) become fully DPI-aware.
VS Designer compatibility: Works without changes. The ModuleInitializer does not run in the designer (only when the assembly is loaded at runtime). The OnHandleCreated and OnDpiChangedAfterParent methods only execute at runtime, not during design-time.
Accessibility impact: No negative impact. High DPI support improves accessibility for users with high-resolution displays.
Localization impact: None. DPI scaling is independent of localization. The solution does not introduce any strings or localizable resources.
Background and motivation
Currently, enabling high DPI awareness (PerMonitorV2) in WinForms applications requires manual setup in Program.cs using Application.SetHighDpiMode. This approach has several limitations:
Developers often forget to set it or set it incorrectly.
It does not handle runtime DPI changes when moving between monitors with different scaling.
Custom controls that use SkiaSharp or direct GDI+ drawing need additional code to rescale properly.
This proposal introduces a zero-configuration, plug-and-play solution that automatically enables PerMonitorV2 DPI awareness as soon as the assembly loads (via ModuleInitializer), and provides a clean pattern for handling runtime DPI changes in custom controls. The solution works across .NET Framework 4.8 to .NET 8+.
API Proposal
API Usage
Step 1: Automatic DPI initialization (consumer perspective)
A developer just needs to reference the library. The ModuleInitializer runs automatically when the assembly loads:
Step 2: Handling runtime DPI changes in custom controls
Step 3: Native WinForms controls work automatically
Standard controls (Button, TextBox, DataGridView, etc.) scale automatically because the process is DPI-aware. No additional code is required.
Alternative Designs
Manual approach (current status quo):
Calling Application.SetHighDpiMode(HighDpiMode.PerMonitorV2) in Program.cs.
Downside: No runtime DPI change handling; easy to forget; requires extra code.
app.config manifest approach:
Declaring DPI awareness in the application manifest.
Downside: Not flexible; doesn't handle runtime changes; requires manifest editing.
Per-control scaling using DpiChanged event:
Subscribing to the DpiChanged event on each control.
Downside: Verbose; easy to miss controls; high maintenance.
Risks
Breaking changes: None. The solution is additive and opt-in via library reference.
Performance: The ModuleInitializer runs once at assembly load (negligible overhead). The OnDpiChangedAfterParent handler runs only when the control's DPI changes (rare event). The S() helper is a simple multiplication.
Compatibility:
Works on Windows 10/11 with PerMonitorV2.
Falls back to SetProcessDPIAware on older Windows (7/8).
Silently fails if the OS doesn't support DPI awareness.
The conditional ModuleInitializerAttribute ensures compilation on .NET Framework 4.8 without errors.
Potential issues:
Some very old applications (Windows 7 without updates) may not support SetProcessDpiAwarenessContext. The try-catch handles this gracefully with a fallback.
Testing: Verified on .NET Framework 4.8, and .NET 8, with both standard WinForms controls and SkiaSharp-based custom rendering.
Will this feature affect UI controls?
Yes, but positively: all controls (both standard and custom) become fully DPI-aware.
VS Designer compatibility: Works without changes. The ModuleInitializer does not run in the designer (only when the assembly is loaded at runtime). The OnHandleCreated and OnDpiChangedAfterParent methods only execute at runtime, not during design-time.
Accessibility impact: No negative impact. High DPI support improves accessibility for users with high-resolution displays.
Localization impact: None. DPI scaling is independent of localization. The solution does not introduce any strings or localizable resources.
VideoCompressorResizeCompressVideo2026_06_08_06_47_07.mp4