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:

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:

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.