Compatibility guide
NetForms is a copy of Windows Forms. Its API reference is Microsoft's: every type, member, event and default value is meant to be exactly what learn.microsoft.com/dotnet/api/system.windows.forms and the Windows Forms documentation describe. This guide covers only what that documentation cannot tell you:
- What runs NetForms — .NET versions, operating systems.
- Which projects move over, and which do not.
- Controls and components — status of each toolbox item.
- Subsystems — layout, drawing, text, resources, data binding, clipboard, printing…
- Windows-only API —
Handle,WndProc, P/Invoke, COM. - Intentional differences from WinForms.
- How compatibility is measured.
- What comes next — the missing API real code uses, in order.
The member-by-member list — what exists and what is missing for each of the 1254 public types of
System.Windows.Forms and System.Drawing.Common — is generated: API coverage.
State as of version 0.1.0-preview.3 (September 2026).
1. What runs NetForms
.NET
| Target framework | Works? | Why |
|---|---|---|
net10.0 |
✅ Yes — the only one | The packages ship lib/net10.0 only. |
net10.0-windows |
✅ Windows only | For "Windows only" projects that want NetForms rendering (netforms-convert --target windows). The -windows TFM does not build on Linux. |
net9.0, net8.0, net7.0, net6.0, net5.0, netcoreapp3.1 |
❌ No | NuGet fails with NU1202: Package NetForms … is not compatible with net8.0. Retarget to net10.0 — the converter does it. |
net8.0-windows + UseWindowsForms (any -windows TFM with the real WinForms) |
❌ Not on Linux | NETSDK1100 at build; with EnableWindowsTargeting=true it builds, then fails at start: Framework: 'Microsoft.WindowsDesktop.App' … No frameworks were found. This is exactly what NetForms replaces. |
.NET Framework 2.0 – 4.8.1 (net48, net472, …) |
❌ Not directly | NetForms is not a .NET Framework library. The converter moves such projects to SDK-style net10.0 (see §2). |
netstandard2.0/2.1 libraries |
✅ If they do not use WinForms | A .NET Standard library cannot reference WinForms anyway; plain logic libraries work as-is. |
Mono (mono, msbuild from Mono) |
❌ No | Mono has its own old System.Windows.Forms on libgdiplus; NetForms needs the .NET 10 runtime. |
You need the .NET 10 SDK to build and the .NET 10 runtime to run (or publish self-contained).
Operating systems
| OS | Status |
|---|---|
| Windows 10 / 11, x64 and arm64 | ✅ Supported, tested in CI (windows-latest). |
| Linux x64 / arm64 with X11, or Wayland through XWayland | ✅ Supported, tested in CI (ubuntu-latest), on Ubuntu 24.04/26.04 and WSL. |
| macOS | ⚠️ Not a goal of this release. Avalonia and SkiaSharp run there and the native libraries are shipped, but nothing is tested. |
| Windows 7 / 8.1, 32-bit Windows, Linux x86/ARM32 | ❌ .NET 10 does not run there, or the natives are not shipped. |
| Browser (WebAssembly), Android, iOS | ❌ Not a target. WinForms is a desktop API. |
Linux packages an application needs at run time: the .NET 10 runtime (with ICU), fontconfig, libX11,
libICE, libSM (Avalonia's X11 backend) and at least one TrueType font family. A desktop distribution has
all of them; the commands for Debian/Ubuntu/Astra, Fedora/RED OS and ALT are in
Install and set up.
When Segoe UI (WinForms' default font) is not installed, the closest installed sans-serif family is
used; text metrics then differ slightly from Windows (see §4, Text).
2. Which projects move over
| What you have | What happens |
|---|---|
SDK-style WinForms project, .NET Core 3.1 – .NET 10 (<UseWindowsForms>true</UseWindowsForms>) |
✅ netforms-convert App.csproj --apply: UseWindowsForms → PackageReference NetForms, net8.0-windows → net10.0, the two implicit usings spelled out. Code is not touched. |
Old-format .NET Framework 2.0 – 4.8.1 project (ToolsVersion, packages.config, <Reference Include="System.Windows.Forms" />) |
✅ The converter rewrites it to SDK-style itself (no upgrade-assistant needed): file list, DependentUpon, resources, packages.config → PackageReference, .snk signing, AssemblyInfo.cs. Non-WinForms libraries of the same solution are converted to net10.0 too. |
Whole solution (.sln, .slnx) or folder |
✅ netforms-convert MySolution.sln --apply converts every project. |
VB.NET WinForms project (.vbproj) |
❌ Not supported. The designer, the templates and the converter are C#-only; the Microsoft.VisualBasic application framework (My.Application, WindowsFormsApplicationBase) is not implemented. |
C++/CLI WinForms project (.vcxproj) |
❌ C++/CLI is Windows-only in .NET. |
WPF, or WinForms hosting WPF (ElementHost, UseWPF) |
❌ Not WinForms. The converter reports UseWPF. |
Project that uses a NuGet package with FrameworkReference Microsoft.WindowsDesktop.App |
❌ That package demands the real Windows Desktop runtime (NETSDK1136). Look for a cross-platform version of the package. |
Project using BinaryFormatter (directly, or in .resx other than ImageList images) |
❌ BinaryFormatter was removed from .NET 9+ — on every OS, not only in NetForms. ImageList.ImageStream from the VS designer is read by NetForms itself. |
Project using WebView2, CefSharp, ActiveX (AxHost), COM references |
❌ Windows-only native components. The converter reports COMReference as an error. |
| Third-party WinForms control packages from NuGet (ZedGraph, OxyPlot.WindowsForms, ScottPlot.WinForms, FastColoredTextBox, ObjectListView, DockPanelSuite…) | ❌ Not yet. Checked with those six on 2026-09-24: packages built for .NET Framework compile against the strong-named System.Windows.Forms, PublicKeyToken=b77a5c561934e089, which NetForms' facade is not, so the build stops with CS0012; packages built for net*-windows demand the Windows Desktop runtime (NETSDK1136, DockPanelSuite). Controls whose source you include in your project compile like your own code. |
The converter never guesses: before --apply it prints what it would change and every place that will
not work on Linux (with file and line), and after it the original project is kept next to the new one
as *.csproj.winforms.bak. See Migrating.
Measured on a corpus of real projects (tests/corpus/corpus.json): 7 of 7 of the customer's
.NET Framework 4.8/4.8.1 projects and 28 of 45 open-source WinForms projects convert and build with no
manual edit. Of the 17 that do not, 6 use BinaryFormatter and 4 Windows-only components (WebView2, CefSharp, a
package that demands the Windows Desktop runtime) — the last rows of the table; 5 need API NetForms does not have
yet (printing, ImageList.Images.Add(string, Icon), LinkLabel.OverrideCursor, Visual Basic's
Microsoft.VisualBasic.Devices); 2 stop on a package (a build task that fails on .NET 10, a package reference the
converter does not carry over). What gets added next: § 8.
3. Controls and components
Legend. Works — implemented, painted by NetForms, behaviour checked against real WinForms by the diff tests. API: complete — every public/protected member exists; N missing — see API coverage for the list.
Common controls
| Control | Status | Notes |
|---|---|---|
Button |
✅ Works · 1 missing | Image, ImageList, TextImageRelation, FlatStyle, FlatAppearance, DialogResult, AcceptButton/CancelButton. |
CheckBox |
✅ Works · 1 missing | Three-state, Appearance.Button, AutoSize metrics identical to VS (checkBox1 → 83×19). |
CheckedListBox |
✅ Works · 2 missing | |
ComboBox |
✅ Works · 4 missing | DropDown, DropDownList, Simple; the list opens outside the form. DataSource with DisplayMember/ValueMember (lists, DataTable, DataSet paths), the selection following the data source's position. AutoCompleteMode is stored, suggestions are not shown yet. |
DateTimePicker |
✅ Works · 1 missing | Custom formats, field editing with arrows, drop-down calendar, ShowUpDown, ShowCheckBox. |
Label |
✅ Works · 12 missing | Missing: Image/ImageList on a label, PreferredWidth/Height. |
LinkLabel |
✅ Works · 3 missing | |
ListBox |
✅ Works · 7 missing | Owner draw, multi-select, DataSource/DisplayMember/ValueMember as in ComboBox. Missing: CustomTabOffsets, Sort() override hook. |
ListView |
✅ Works · 43 missing | All views (Details, List, SmallIcon, LargeIcon, Tile), groups, check boxes, label edit, sorting. Missing: VirtualMode, column reordering by drag, HotTracking, insertion mark. |
MaskedTextBox |
✅ Works · 1 missing | Masks via the same MaskedTextProvider WinForms uses. |
MonthCalendar |
✅ Works · 8 missing | One month is shown (CalendarDimensions is stored). |
NotifyIcon |
✅ Works · API complete | System tray via the OS (StatusNotifierItem on Linux); the context menu is drawn by the shell. See §6. |
NumericUpDown |
✅ Works · 3 missing | |
PictureBox |
✅ Works · 9 missing | All SizeModes. Load()/Load(path) read a file; setting ImageLocation alone does not load it, and URLs are not fetched. Missing: LoadAsync. |
ProgressBar |
✅ Works · 5 missing | Marquee included. |
RadioButton |
✅ Works · 1 missing | |
RichTextBox |
✅ Works · 1 missing | Own RTF reader/writer: fonts, colours, bold/italic/underline, bullets, alignment, links, undo. Not yet: numbered lists, images/OLE objects, justify, drag-and-drop, IME. |
TextBox |
✅ Works · 1 missing | Selection, undo, clipboard, context menu, multiline, password, CharacterCasing. AutoCompleteCustomSource is stored, suggestions are not shown. |
ToolTip |
✅ Works · 2 missing | |
TreeView |
✅ Works · 9 missing | Check boxes, images, label edit, owner draw. Missing: ItemDrag, NodeMouseHover. |
WebBrowser |
❌ Missing | Internet Explorer control; will not come (see §5). |
DomainUpDown |
❌ Missing | |
HScrollBar, VScrollBar, TrackBar |
✅ Works |
Containers
| Control | Status | Notes |
|---|---|---|
Panel, GroupBox |
✅ Works · 1 missing each | AutoScroll, AutoSize, BorderStyle. |
FlowLayoutPanel |
✅ Works · API complete | Layout engine ported from dotnet/winforms, including the SetFlowBreak quirk. |
TableLayoutPanel |
✅ Works · 1 missing | Percent/absolute/auto-size rows and columns, spans. |
SplitContainer |
✅ Works · 2 missing | |
TabControl |
✅ Works · 13 missing | Missing: ImageList on tabs, DeselectTab, RightToLeftLayout. |
Splitter |
❌ Missing | Use SplitContainer. |
UserControl |
✅ Works · API complete | |
Form |
✅ Works · 34 missing | Modal/modeless, Owner, TopMost, StartPosition, FormBorderStyle, AcceptButton, KeyPreview, MDI, TopLevel = false. Missing: ShowAsync/ShowDialogAsync (.NET 9+), caption colours and corner preference (Windows 11 only), DpiChanged. |
MDI (IsMdiContainer, MdiParent, LayoutMdi, MdiWindowListItem) |
✅ Works |
Menus and toolbars
| Control | Status | Notes |
|---|---|---|
MenuStrip, ContextMenuStrip, ToolStrip, StatusStrip |
✅ Works · few missing | All standard items (ToolStripButton, …MenuItem, …DropDownButton, …SplitButton, …ComboBox, …TextBox, …ProgressBar, …Label, …Separator), shortcuts, mnemonics, overflow, professional renderer. Missing: dragging items (AllowItemReorder), LayoutStyle settings objects. |
ToolStripContainer, ToolStripPanel |
❌ Missing | Docked, draggable toolbars. |
MainMenu, ContextMenu, ToolBar, StatusBar, DataGrid |
❌ Missing | The .NET Framework 1.x controls — removed from .NET itself in .NET Core 3.1; they do not work in real WinForms on .NET 10 either. Replace them with MenuStrip, ContextMenuStrip, ToolStrip, StatusStrip, DataGridView. |
Data
| Control | Status | Notes |
|---|---|---|
DataGridView |
✅ Works · 242 missing | Columns of every kind (text, check box, combo box, button, link, image) and per-cell types (row.Cells[i] = new DataGridViewButtonCell()), CellContentClick, editing, sorting, selection modes, auto-size policies, DataSource/DataMember binding through the form's BindingContext (lists, DataTable, a DataSet table, a relation for master-detail; the current row and the source's Position follow each other; relations are not columns), frozen columns, virtual scrolling. Custom cells (a DataGridViewCell subclass overriding Paint) work and get the inherited style, font included; the default styles carry the grid's font and follow it, as in WinForms. Editing is the WinForms model: the cell's EditType control (DataGridViewTextBoxEditingControl, DataGridViewComboBoxEditingControl, or your own IDataGridViewEditingControl — Microsoft's calendar column works as published) in EditingPanel, EditingControlShowing, the dirty cell and CurrentCellDirtyStateChanged, CellValidating/CellParsing/CellValidated and DataError on commit, CellEnter/CellLeave/RowEnter/RowLeave/RowValidating, BeginEdit/EndEdit/CommitEdit/CancelEdit/RefreshEdit, EditMode, typing/F2/Enter/Escape/Tab; the check box cell edits itself (IDataGridViewEditingCell) and commits on leave, as in WinForms. VirtualMode with RowCount, CellValueNeeded/CellValuePushed, RowDirtyStateNeeded, CancelRowEdit. Missing: the new row's NewRowNeeded/UserAddedRow flow, clipboard copy, the rest of the protected Process*Key/On*Changed hooks and AutoResize* methods. |
BindingSource |
✅ Works · API: complete | The WinForms implementation itself (vendored from dotnet/winforms): lists, DataTable, a DataSet with a table as DataMember, master-detail with a DataRelation as the DataMember of a second BindingSource, Position, Filter, Sort, AddNew, CurrencyManager. |
BindingNavigator |
❌ Missing | |
ADO.NET itself (DataSet, DataTable, DataAdapter, providers) |
Part of .NET, not of WinForms: works on Linux as it is. Edits made in a bound grid set RowState, so adapter.Update(table) saves them. The provider decides the platform: SQL Server (Microsoft.Data.SqlClient), PostgreSQL, MySQL, SQLite, Firebird, Oracle run on Linux; Access through System.Data.OleDb is Windows-only (PlatformNotSupportedException on Linux, the converter warns). |
|
Control.DataBindings, Binding, BindingContext, CurrencyManager |
✅ Works · API: complete | The WinForms implementation itself (vendored from dotnet/winforms), with its rules: a control binds once it is created and has a BindingContext (a form gives both); the default DataSourceUpdateMode.OnValidation writes the value when the control validates; Format/Parse, FormatString, NullValue, BindingComplete (with formatting enabled), ErrorProvider over IDataErrorInfo. The designer reads and writes DataBindings.Add(new Binding(...)) as Visual Studio does. |
PropertyGrid |
✅ Works · 31 missing | Categories, type editors, expandable objects. Missing: the command pane and its colours. |
Components and dialogs
| Component | Status |
|---|---|
Timer, ImageList, ErrorProvider, HelpProvider* , BackgroundWorker |
✅ (HelpProvider ❌ missing; BackgroundWorker is part of .NET itself and works as-is) |
MessageBox, TaskDialog |
✅ Own dialogs in the NetForms theme; button captions follow the UI language (English, Russian). |
OpenFileDialog, SaveFileDialog, FolderBrowserDialog |
✅ Native dialogs of the OS (portal / GTK on Linux). A few properties missing (ClientGuid, custom places). |
ColorDialog, FontDialog |
✅ Own dialogs. |
PrintDialog, PrintPreviewDialog, PrintPreviewControl, PageSetupDialog, PrintDocument |
❌ Missing — the whole System.Drawing.Printing namespace. Next on the list. |
NotifyIcon |
✅ See above. |
4. Subsystems
| Area | Status |
|---|---|
| Message loop | Application.Run(Form), Run(ApplicationContext), DoEvents, Exit, Idle, ThreadException (an unhandled exception in an event handler shows the continue/quit dialog, as in WinForms), IMessageFilter (sees WM_KEYDOWN/WM_KEYUP). ApplicationConfiguration.Initialize() works. Control.Invoke/BeginInvoke/InvokeAsync marshal to the UI thread. |
| Layout | Anchor, Dock, Margin/Padding, AutoSize/AutoSizeMode, MinimumSize/MaximumSize, SuspendLayout/ResumeLayout, AutoScroll. Coordinates match real WinForms — checked by the diff tests on every build. |
| Focus and keyboard | Tab order, TabStop, mnemonics (&File), AcceptButton/CancelButton, ProcessCmdKey/ProcessDialogKey/IsInputKey/PreviewKeyDown, both WinForms focus-event orders (Select() vs Focus()), validation (Validating/Validated, AutoValidate). |
| Mouse | Click, double click, capture, wheel, enter/leave/hover, cursors (named cursors; a cursor from a .cur file shows the arrow). Cursor.Position can be read, not set. |
Drawing (System.Drawing) |
Graphics on SkiaSharp: lines, shapes, paths, curves, regions, clipping, transforms, LinearGradientBrush, HatchBrush, TextureBrush, images with ImageAttributes/ColorMatrix, LockBits, RotateFlip, icons, ControlPaint. Missing: PathGradientBrush, BufferedGraphics, ImageAnimator (animated GIF), metafiles (Metafile, EMF/WMF); Graphics.CopyFromScreen throws NotSupportedException. Images are decoded by Skia (PNG, JPEG, BMP, GIF — first frame, ICO, WebP); Image.Save writes PNG, JPEG and WebP, while BMP and GIF throw NotSupportedException. |
| Text | TextRenderer.MeasureText/DrawText is the reference (GDI metrics), Graphics.MeasureString/DrawString follows GDI+ rules. With the same font file the numbers equal Windows; with a substitute font (no Segoe UI on Linux) they differ by a pixel or two. RightToLeftLayout mirroring is not implemented. |
| DPI | Everything is laid out in 96-DPI logical pixels and scaled by the platform to the screen (sharp on HiDPI). AutoScaleMode/AutoScaleDimensions are kept; DeviceDpi is always 96 and DpiChanged is never raised. |
| Theme | One built-in light theme that looks like WinForms with visual styles. Application.SetColorMode(Dark) is accepted, dark mode is not drawn yet. VisualStyleRenderer types exist; drawing goes through the NetForms theme. |
Resources (.resx) |
Strings, images, icons, typed values, ResXFileRef — read at run time through ComponentResourceManager, as in WinForms. The designer opens Localizable = true forms but does not write them yet. ImageList.ImageStream (BinaryFormatter in the VS designer's format) is read by NetForms. Other BinaryFormatter resources are not (see §2). |
| Settings | Properties.Settings (ApplicationSettingsBase), ConfigurationManager, app.config compile and run: the NetForms package brings System.Configuration.ConfigurationManager, as the Windows Desktop runtime does. |
| Clipboard | Text goes through the OS clipboard both ways. Images, file lists, audio and custom formats work inside the application only. |
| Drag and drop | Events and AllowDrop exist so code compiles; the platform does not start or deliver drags yet (DoDragDrop returns None). |
| IME | Committed text from input methods (Chinese, Japanese, Korean…) arrives in KeyPress/TextBox. The composition string is shown by the input method's own window, not inline. |
| Accessibility | ❌ Not yet. AccessibleObject and UI Automation are missing; AccessibleName/AccessibleDescription are stored. Screen readers do not see NetForms controls. |
| Printing | ❌ Missing (see §3). |
| Help | Help.ShowHelp opens files and URLs with the system program; F1 raises HelpRequested. CHM viewers exist on Windows only. |
| Sound | System.Media.SoundPlayer is part of .NET and Windows-only there; NetForms does not add one. |
5. Windows-only API
NetForms controls have no native window (no HWND). Everything that assumes one compiles but does nothing, or is not there:
| API | In NetForms |
|---|---|
Control.Handle, Form.Handle, ImageList.Handle |
IntPtr.Zero. IsHandleCreated, HandleCreated, HandleDestroyed follow the WinForms life cycle. |
WndProc, DefWndProc, CreateParams, CreateHandle, FromHandle, NativeWindow |
Overrides compile; the platform never calls them, messages are not synthesised. NativeWindow is missing. |
P/Invoke into user32, gdi32, comctl32, uxtheme, dwmapi, shell32… |
Throws DllNotFoundException on Linux (works on Windows, but the handles you pass are zero). The converter lists every such call with file and line. |
Microsoft.Win32.Registry, Application.UserAppDataRegistry |
Registry is Windows-only in .NET; UserAppDataRegistry is missing. The converter warns. |
ActiveX (AxHost), COM interop, WebBrowser, WebView2, CefSharp |
Not available and not planned. |
SendKeys, InputLanguage, SystemEvents, power status |
Missing. |
Screen |
Real monitors from the platform; SystemInformation returns what NetForms draws with, and Windows 10/11 defaults for the rest. |
6. Intentional differences
Differences that are known, measured and kept on purpose. Everything else that differs from WinForms is a bug — please report it.
- Look. Controls look like WinForms with visual styles, but are drawn by NetForms, not by
uxtheme— pixel identity with Windows is not a goal. The look is the same on Windows and Linux. - Windows-style paths in NetForms file APIs.
Image.FromFile,new Bitmap(path),new Icon(path),Image.Save,PrivateFontCollection.AddFontFileaccept\and ignore case on Linux when the exact name does not exist — soApplication.StartupPath + @"\img\x.png"keeps working.System.IO.Filedoes not do this; the converter warns about such strings. - Drop-down menus are about 10 px narrower: the image column is painted under the items rather than kept in the padding.
NotifyIcon: Linux tray hosts report only primary clicks, so double clicks are synthesised, right-button events arrive only when a context menu opens,MouseMovenever arrives, and the menu is drawn by the shell.ErrorProvidericons do not blink.DataGridView: an unhandledDataErroris not shown in a message box (WinForms shows one); the first cell is not made current when the window is created (WinForms does); aDefaultCellStyleassigned with members unset gets them filled on the object (WinForms returns a filled copy from the getter).Form.TopLevel = false: an embedded form has no frame (WinForms draws one).RichTextBox.Rtfwrites non-ASCII characters as\uN?(RichEdit uses\'hhin the font's code page); both are read.- Negative sizes of an unparented docked control are clamped to 0 immediately (WinForms does it when the window is created).
- System colours:
SystemColors.*are .NET's own table on Linux (the classic Windows palette), the OS palette on Windows. The NetForms theme always paints with the Windows 10/11 light palette.
7. How compatibility is measured
- Diff tests against the real WinForms (
tests/NetForms.Compat, Windows CI): the same scenarios run onSystem.Windows.Formsand on NetForms; positions, sizes, event order, text metrics, design-time attributes and what the designer serializes are compared. The suite: 415/415; on Windows CI it runs with all three oracles of the real WinForms. - Golden rendering tests (offscreen, identical images on Windows and Linux).
- API coverage —
dotnet run --project tools/NetForms.ApiDiff -- --markdown docs/apiregenerates the tables. Today: 664 of 1254 types complete, 163 partial, 427 missing (most of themEventArgs, accessibility, printing and the removed 1.x controls). - Corpus of real projects (
NETFORMS_CORPUS=1, CI jobcorpus): converted and built without manual edits, with the reason for every failure recorded intests/corpus/corpus.json.
8. What comes next
What to add first is decided by the code people write, not by the length of the list:
NetForms.ApiDiff --usage compiles every project of the corpus against the real WinForms and counts each reference
to a type or member NetForms lacks — Missing API by use. Of 25,887 references to the WinForms API in
63 projects (24 repositories), 11 types and members are missing, and each of them stops a build:
| Next | Code that needs it |
|---|---|
Printing: PrintDocument, PrintPageEventArgs, PrintDialog (with them PrintPreviewDialog, PageSetupDialog) |
MDBEditor |
ImageList.Images.Add(string, Icon) |
Surviving-WinForms (GetStockIcon sample) |
LinkLabel.OverrideCursor — the protected property a derived link label sets |
xrails-login-ui (both projects) |
ImageFormat.Icon/Tiff/Wmf, OpenFileDialog.SafeFileName, TabControl.TabPages.Remove, new Font(FontFamily, float, FontStyle, GraphicsUnit, byte) |
MDBEditor, xrails-login-ui |
The corpus already builds almost entirely, so this list is short. Ranking the other missing types takes a wider sample of open-source WinForms code — it only has to compile against the real WinForms, not build with NetForms.