What's new in Windows Forms for .NET 9
This article describes what's new in Windows Forms for .NET 9.
Async forms
Important
This feature set is experimental.
Modern apps require asynchronous communication models. As Windows Forms has grown on .NET, more components require marshaling to an async
method to run on the UI-thread. For example, controls like WebView2, native Windows 10 and Windows 11 APIs, or modern asynchronous libraries like Semantic Kernel. Another scenario would be where you're sharing MVVM ViewModels built around async
with Windows Forms from other UI stacks such as WPF, WinUI, or .NET MAUI.
The following a list of new methods added to support asynchronous scenarios:
- System.Windows.Forms.Form.ShowAsync
- Form.ShowDialogAsync
- TaskDialog.ShowDialogAsync
- Control.InvokeAsync
This API is guarded behind a compiler error because it's experimental. To suppress the error and enable access to the API, add the following PropertyGroup
to your project file:
<PropertyGroup>
<NoWarn>$(NoWarn);WFO5002</NoWarn>
</PropertyGroup>
Tip
You can use the #pragma warning disable WFO5002
directive to suppress the error where it occurs instead of disabling it for the entire project.
BinaryFormatter no longer supported
BinaryFormatter
is considered unsafe because it's vulnerable to deserialization attacks, which can lead to denial of service (DoS), information disclosure, or remote code execution. It was implemented before deserialization vulnerabilities were well understood, and its design doesn't follow modern security best practices.
Starting with .NET 9, its implementation has been removed to prevent these security risks. When BinaryFormatter
is used, the PlatformNotSupportedException
exception is thrown.
Windows Forms used BinaryFormatter
in many scenarios, such as when serializing data for clipboard and drag-and-drop operations, and most importantly, the Windows Forms Designer. Internally, Windows Forms continues to use a safer subset of BinaryFormatter
to handle specific use cases with a known set of types.
Windows Forms for .NET 9 is shipping with analyzers that help you identify times you unknowingly participate in binary serialization.
For more information about BinaryFormatter
, see Windows Forms migration guide for BinaryFormatter.
Dark mode
Important
This feature set is experimental.
Preliminary support for dark mode has been added to Windows Forms, with the goal of finalizing support in .NET 10. The color mode for the app can be set to one of the following values:
SystemColorMode.Classic
—(default) Light mode, the same as previous versions of Windows Forms.SystemColorMode.System
—Respect the light or dark mode set by Windows.SystemColorMode.Dark
—Use dark mode.
To apply a color mode, call Application.SetColorMode(SystemColorMode) in the program startup code:
namespace MyExampleProject;
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
// To customize application configuration such as set high DPI settings or default font,
// see https://aka.ms/applicationconfiguration.
ApplicationConfiguration.Initialize();
Application.SetColorMode(SystemColorMode.Dark);
Application.Run(new Form1());
}
}
Friend Module Program
<STAThread()>
Friend Sub Main(args As String())
Application.SetHighDpiMode(HighDpiMode.SystemAware)
Application.EnableVisualStyles()
Application.SetCompatibleTextRenderingDefault(False)
Application.SetColorMode(SystemColorMode.Dark)
Application.Run(New Form1)
End Sub
End Module
This API is guarded behind a compiler error because it's experimental. To suppress the error and enable access to the API, add the following PropertyGroup
to your project file:
<PropertyGroup>
<NoWarn>$(NoWarn);WFO5001</NoWarn>
</PropertyGroup>
Tip
You can use the #pragma warning disable WFO5001
directive to suppress the error where it occurs instead of disabling it for the entire project.
FolderBrowserDialog enhancements
FolderBrowserDialog
now supports selecting multiple folders, which are stored in the SelectedPaths array. To enable multiple folders, set Multiselect to true
.
System.Drawing new features and enhancements
The System.Drawing library has had many improvements, including wrapping GDI+ effects, support for ReadOnlySpan
, and better interop code generation.
System.Drawing supports GDI+ effects
The System.Drawing library now supports GDI+ bitmap effects, such as blur and tint. Effects have been a part of GDI+, but weren't exposed through System.Drawing until now.
Effects are applied to a Bitmap by calling the Bitmap.ApplyEffect(Effect, Rectangle) method. Provide the effect and an optional Rectangle
for the area to apply the effect on. Use Rectangle.Empty to process the entire image.
The System.Drawing.Imaging.Effects namespace contains the effects you can apply:
- BlackSaturationCurveEffect
- BlurEffect
- BrightnessContrastEffect
- ColorBalanceEffect
- ColorCurveEffect
- ColorLookupTableEffect
- ColorMatrixEffect
- ContrastCurveEffect
- CurveChannel
- DensityCurveEffect
- ExposureCurveEffect
- GrayScaleEffect
- HighlightCurveEffect
- InvertEffect
- LevelsEffect
- MidtoneCurveEffect
- ShadowCurveEffect
- SharpenEffect
- TintEffect
- VividEffect
- WhiteSaturationCurveEffect
System.Drawing supports Span
Many methods that accepted arrays have been enhanced to also accept ReadOnlySpan
. For example, methods such as GraphicsPath.AddLines(ReadOnlySpan<Point>), Graphics.DrawLines(Pen, ReadOnlySpan<Point>), and DrawPolygon(Pen, ReadOnlySpan<Point>), accept an array or ReadOnlySpan
.
Use CsWin32 for interop
All interop code has been replaced by CsWin32, a C# P/Invoke source generator.
ToolStrip
The following improvements have been added to the ToolStrip and ToolStripItem controls.
A new property was added to
ToolStrip
, AllowClickThrough.When set to
true
, the control can be interacted with while the form is unfocused.
Back when .NET Core 3.1 was released, all Menu
-related controls, such as MainMenu
and MenuItem
, were removed. ToolStrip
and ToolStripMenuItem
should be used instead. However, ToolStripItem
, the base class for ToolStripMenuItem
, didn't have a replacement for the MenuItem.Select
event. This event was raised when the mouse or keyboard is used to highlight the item.
.NET 9 has added ToolStripItem.SelectedChanged, which can be used to detect when a menu item is highlighted.
.NET Desktop feedback