NetForms

Совместимость

NetForms — копия Windows Forms. Справочник по API — от Microsoft: каждый тип, член, событие и значение по умолчанию должны быть ровно такими, как описано в learn.microsoft.com/ru-ru/dotnet/api/system.windows.forms и в документации по Windows Forms. Здесь — только то, чего эта документация сказать не может:

  1. На чём работает NetForms — версии .NET, операционные системы.
  2. Какие проекты переносятся, а какие нет.
  3. Контролы и компоненты — состояние каждого элемента панели.
  4. Подсистемы — раскладка, рисование, текст, ресурсы, данные, буфер обмена, печать…
  5. API, существующий только в Windows — Handle, WndProc, P/Invoke, COM.
  6. Осознанные отличия от WinForms.
  7. Как измеряется совместимость.
  8. Что дальше — недостающий API, который использует реальный код, по порядку.

Полный список по членам — что есть и чего нет для каждого из 1254 публичных типов System.Windows.Forms и System.Drawing.Common — генерируется автоматически: покрытие API (на английском).

Состояние на версию 0.1.5 (октябрь 2026).


1. На чём работает NetForms

.NET

Целевая платформа (TFM) Работает? Почему
net10.0 ✅ Да — только она В пакетах есть только lib/net10.0.
net10.0-windows ✅ Только Windows Для проектов «только под Windows», которым нужна отрисовка NetForms (netforms-convert --target windows). TFM с -windows на Linux не собирается.
net9.0, net8.0, net7.0, net6.0, net5.0, netcoreapp3.1 ❌ Нет NuGet выдаёт NU1202: Package NetForms … is not compatible with net8.0. Перейдите на net10.0 — конвертер делает это сам.
net8.0-windows + UseWindowsForms (любой TFM с -windows и настоящим WinForms) ❌ Не на Linux При сборке — NETSDK1100; с EnableWindowsTargeting=true собирается, но при запуске: Framework: 'Microsoft.WindowsDesktop.App' … No frameworks were found. Именно это NetForms и заменяет.
.NET Framework 2.0 – 4.8.1 (net48, net472, …) ❌ Не напрямую NetForms — не библиотека .NET Framework. Конвертер переводит такие проекты в SDK-формат на net10.0 (см. §2).
Библиотеки netstandard2.0/2.1 ✅ Если не используют WinForms Библиотека .NET Standard и так не может ссылаться на WinForms; обычные библиотеки с логикой работают как есть.
Mono (mono, msbuild из Mono) ❌ Нет У Mono свой старый System.Windows.Forms на libgdiplus; NetForms нужна среда .NET 10.

Для сборки нужен .NET 10 SDK, для запуска — среда выполнения .NET 10 (или публикация self-contained, со средой внутри).

Операционные системы

ОС Состояние
Windows 10 / 11, x64 и arm64 ✅ Поддерживается, проверяется в CI (windows-latest).
Linux x64 / arm64 с X11 или Wayland через XWayland ✅ Поддерживается, проверяется в CI (ubuntu-latest), на Ubuntu 24.04/26.04 и WSL.
macOS ⚠️ Не цель этой версии. Avalonia и SkiaSharp там работают и нативные библиотеки в пакетах есть, но ничего не проверяется.
Windows 7 / 8.1, 32-битная Windows, Linux x86/ARM32 ❌ .NET 10 там не работает, либо нет нативных библиотек.
Браузер (WebAssembly), Android, iOS ❌ Не цель. WinForms — API для настольных приложений.

Пакеты Linux, нужные приложению при запуске: среда .NET 10 (с ICU), fontconfig, libX11, libICE, libSM (X11-бэкенд Avalonia) и хотя бы одно семейство TrueType-шрифтов. В настольном дистрибутиве всё это уже есть; команды для Debian/Ubuntu/Astra, Fedora/РЕД ОС и ALT — в разделе Установка и настройка.

Если шрифт Segoe UI (шрифт WinForms по умолчанию) не установлен, берётся ближайший установленный шрифт без засечек; метрики текста тогда немного отличаются от Windows (см. §4, «Текст»).


2. Какие проекты переносятся

Что у вас Что будет
WinForms-проект в SDK-формате, .NET Core 3.1 – .NET 10 (<UseWindowsForms>true</UseWindowsForms>) ✅ netforms-convert App.csproj --apply: UseWindowsForms → PackageReference NetForms, net8.0-windows → net10.0, два неявных using прописываются явно. Код не трогается.
Проект .NET Framework 2.0 – 4.8.1 в старом формате (ToolsVersion, packages.config, <Reference Include="System.Windows.Forms" />) ✅ Конвертер сам переводит его в SDK-формат (upgrade-assistant не нужен): список файлов, DependentUpon, ресурсы, packages.config → PackageReference, подпись .snk, AssemblyInfo.cs. Библиотеки того же решения без WinForms тоже переводятся на net10.0.
Решение целиком (.sln, .slnx) или папка ✅ netforms-convert MySolution.sln --apply переводит каждый проект.
WinForms-проект на VB.NET (.vbproj) ❌ Не поддерживается. Дизайнер, шаблоны и конвертер — только для C#; прикладная модель Microsoft.VisualBasic (My.Application, WindowsFormsApplicationBase) не реализована.
WinForms-проект на C++/CLI (.vcxproj) ❌ C++/CLI в .NET есть только под Windows.
WPF или WinForms с WPF внутри (ElementHost, UseWPF) ❌ Это не WinForms. Конвертер сообщает об UseWPF.
Проект с NuGet-пакетом, у которого FrameworkReference Microsoft.WindowsDesktop.App ❌ Такой пакет требует настоящую среду Windows Desktop (NETSDK1136). Ищите кроссплатформенную версию пакета.
Проект с BinaryFormatter (напрямую или в .resx, кроме картинок ImageList) ❌ BinaryFormatter удалён из .NET 9+ — на любой ОС, не только в NetForms. ImageList.ImageStream из дизайнера VS NetForms читает сам.
Проект с WebView2, CefSharp, ActiveX (AxHost), COM-ссылками ❌ Нативные компоненты только для Windows. Конвертер отмечает COMReference как ошибку.
Библиотеки контролов, собранные под NetForms, и собственные контролы проекта в дизайнере ✅ Панель элементов их показывает, холст выполняет; пакеты NuGet, .dll и другие проекты подключаются командой Add Control Library (Библиотеки элементов управления в дизайнере).
Сторонние пакеты контролов WinForms из NuGet (ZedGraph, OxyPlot.WindowsForms, ScottPlot.WinForms, FastColoredTextBox, ObjectListView, DockPanelSuite…) ❌ Пока нет. Проверено на этих шести 2026-09-24: пакеты для .NET Framework собраны против подписанной сборки System.Windows.Forms, PublicKeyToken=b77a5c561934e089, а фасад NetForms ею не является, и сборка останавливается с CS0012; пакеты для net*-windows требуют среду Windows Desktop (NETSDK1136, DockPanelSuite). Контролы, исходники которых лежат в вашем проекте, компилируются как ваш собственный код.

Конвертер ничего не угадывает: без --apply он показывает, что изменит, и каждое место, которое не будет работать на Linux (с файлом и строкой); после --apply исходный проект лежит рядом с новым как *.csproj.winforms.bak. Подробнее — Перевод WinForms-проекта.

Измерено на корпусе реальных проектов (tests/corpus/corpus.json): 7 из 7 проектов заказчика на .NET Framework 4.8/4.8.1 и 31 из 45 открытого WinForms-проекта переводятся и собираются без ручных правок. Из 14 непрошедших 6 используют BinaryFormatter и 4 — компоненты только для Windows (WebView2, CefSharp, пакет, требующий среду Windows Desktop), это последние строки таблицы; 1 ссылается на готовую .dll, собранную под WinForms из .NET Framework, 1 — на Microsoft.VisualBasic.Devices из Visual Basic; 2 останавливаются на пакете (его задача сборки падает на .NET 10; ссылку на пакет конвертер не переносит). API WinForms, которого им не хватало бы, в корпусе больше нет: см. § 8.


3. Контролы и компоненты

Обозначения. Работает — реализовано, рисуется NetForms, поведение сверено с настоящим WinForms дифф-тестами. API полный — есть каждый публичный и защищённый член; нет N — список в покрытии API.

Основные контролы

Контрол Состояние Примечания
Button ✅ Работает · нет 1 Image, ImageList, TextImageRelation, FlatStyle, FlatAppearance, DialogResult, AcceptButton/CancelButton.
CheckBox ✅ Работает · нет 1 Три состояния, Appearance.Button, размеры AutoSize как в VS (checkBox1 → 83×19).
CheckedListBox ✅ Работает · нет 2
ComboBox ✅ Работает · нет 4 DropDown, DropDownList, Simple; список открывается за пределами формы. DataSource с DisplayMember/ValueMember (списки, DataTable, пути в DataSet), выбор следует за позицией источника данных. AutoCompleteMode сохраняется, подсказки пока не показываются.
DateTimePicker ✅ Работает · нет 1 Свои форматы, правка полей стрелками, выпадающий календарь, ShowUpDown, ShowCheckBox.
Label ✅ Работает · нет 12 Нет: Image/ImageList у надписи, PreferredWidth/Height.
LinkLabel ✅ Работает · API полный Ссылки, цвета посещённых, LinkClicked; OverrideCursor и PointInLink для наследников.
ListBox ✅ Работает · нет 7 Owner draw, множественный выбор, DataSource/DisplayMember/ValueMember, как у ComboBox. Нет: CustomTabOffsets, переопределяемого Sort().
ListView ✅ Работает · нет 38 Все виды (Details, List, SmallIcon, LargeIcon, Tile), группы, флажки, правка подписей, сортировка, ItemDrag (нажатие на один из нескольких выделенных элементов сохраняет выделение для перетаскивания), ItemMouseHover. Нет: VirtualMode, перестановки столбцов мышью, HotTracking, метки вставки.
MaskedTextBox ✅ Работает · нет 1 Маски через тот же MaskedTextProvider, что и в WinForms.
MonthCalendar ✅ Работает · нет 8 Показывается один месяц (CalendarDimensions сохраняется).
NotifyIcon ✅ Работает · API полный Значок в трее через ОС (StatusNotifierItem на Linux); контекстное меню рисует оболочка. См. §6.
NumericUpDown ✅ Работает · нет 2 У UpDownBase защищённые хуки WinForms (OnChanged, OnTextBoxTextChanged(object, EventArgs), OnTextBoxKeyDown, …) для своих счётчиков.
PictureBox ✅ Работает · нет 9 Все SizeMode. Load()/Load(path) читают файл; одно присваивание ImageLocation его не загружает, URL не скачиваются. Нет LoadAsync.
ProgressBar ✅ Работает · нет 5 Включая Marquee.
RadioButton ✅ Работает · нет 1
RichTextBox ✅ Работает · нет 1 Своё чтение и запись RTF: шрифты, цвета, жирный/курсив/подчёркивание, маркированные списки, выравнивание, ссылки, отмена. Пока нет: нумерованных списков, картинок/OLE-объектов, выравнивания по ширине, перетаскивания, IME.
TextBox ✅ Работает · нет 1 Выделение, отмена, буфер обмена, контекстное меню, многострочный режим, пароль, CharacterCasing. AutoCompleteCustomSource сохраняется, подсказки не показываются.
ToolTip ✅ Работает · нет 2
TreeView ✅ Работает · API полный Флажки, картинки по индексу и по ключу, картинки состояния (StateImageList, StateImageKey), правка подписей, owner draw, ItemDrag (левой и правой кнопкой), NodeMouseHover, HotTracking, подсказки узлов (ShowNodeToolTips), свой ContextMenuStrip у узла, GetItemRenderStyles, TreeNode.Handle/FromHandle, сериализация TreeNode. Как в системном дереве, узел выделяется при отпускании кнопки: перетаскивание узла его не выделяет, правая кнопка не выделяет. RightToLeftLayout хранится, зеркалирования нет (см. §4, Текст).
WebBrowser ❌ Нет Контрол Internet Explorer; не появится (см. §5).
DomainUpDown ✅ Работает · API полный Реализация WinForms: Items, Sorted, Wrap, SelectedItemChanged; ввод выбирает элемент, начинающийся с набранного, в режиме «только чтение» — переход по первой букве.
HScrollBar, VScrollBar, TrackBar ✅ Работают

Контейнеры

Контрол Состояние Примечания
Panel, GroupBox ✅ Работают · API полный AutoScroll, AutoSize, BorderStyle, DockPadding, состояние прокрутки (HScroll/VScroll, GetScrollState), ScrollToControl (переопределите, чтобы панель не прыгала к контролу с фокусом), SetAutoScrollMargin, специальные возможности (Client, Grouping). GroupBoxRenderer рисует рамку группы для owner-drawn контролов; ButtonRenderer, CheckBoxRenderer, RadioButtonRenderer, ComboBoxRenderer, ProgressBarRenderer и ScrollBarRenderer рисуют части остальных контролов в теме NetForms.
FlowLayoutPanel ✅ Работает · API полный Движок раскладки перенесён из dotnet/winforms, вместе с особенностью SetFlowBreak.
TableLayoutPanel ✅ Работает · нет 1 Строки и столбцы в процентах, пикселях и по содержимому, объединение ячеек.
SplitContainer ✅ Работает · нет 1 Раскладка как у WinForms (пропорция сохраняется при изменении размера, FixedPanel, BeginInit/EndInit, рамка — у панелей); при перетаскивании видна полоса, панели сдвигаются, когда кнопку отпустили. Пока нет: перемещения сплиттера стрелками.
TabControl ✅ Работает · нет 12 TabPages.Add/Insert по ключу, тексту и картинке. Нет: ImageList у вкладок, DeselectTab, RightToLeftLayout.
Splitter ✅ Работает · API полный Пристыкованный разделитель WinForms 1.0: MinSize, MinExtra, SplitPosition, SplitterMoving/SplitterMoved, Escape отменяет. Полоса при перетаскивании — штриховка поверх соседей (Win32 инвертирует пиксели).
UserControl ✅ Работает · API полный
Form ✅ Работает · нет 34 Модальные и немодальные, Owner, TopMost, StartPosition, FormBorderStyle, AcceptButton, KeyPreview, MDI, TopLevel = false. Нет: ShowAsync/ShowDialogAsync (.NET 9+), цветов заголовка и скругления углов (только Windows 11), DpiChanged.
MDI (IsMdiContainer, MdiParent, LayoutMdi, MdiWindowListItem) ✅ Работает

Меню и панели инструментов

Контрол Состояние Примечания
MenuStrip, ContextMenuStrip, ToolStrip, StatusStrip ✅ Работают · нет немногого Все стандартные элементы (ToolStripButton, …MenuItem, …DropDownButton, …SplitButton, …ComboBox, …TextBox, …ProgressBar, …Label, …Separator), горячие клавиши, мнемоники, переполнение, professional-рендерер. Нет: перетаскивания элементов (AllowItemReorder), объектов настроек LayoutStyle.
ToolStripContainer, ToolStripPanel ✅ Работает Полосы рядами с каждой стороны, перетаскиваются за ручку вдоль ряда, в другой ряд и на другую сторону; Join, Rows, Locked, RowMargin. Полоса, которой не хватает места в ряду, наезжает на следующую, а не уводит пункты в переполнение.
MainMenu, ContextMenu, ToolBar, StatusBar, DataGrid ❌ Нет Контролы .NET Framework 1.x — удалены из самого .NET в .NET Core 3.1; в настоящем WinForms на .NET 10 они тоже не работают. Замените на MenuStrip, ContextMenuStrip, ToolStrip, StatusStrip, DataGridView.

Данные

Контрол Состояние Примечания
DataGridView ✅ Работает · нет 236 Столбцы всех видов (текст, флажок, список, кнопка, ссылка, картинка) и типы отдельных ячеек (row.Cells[i] = new DataGridViewButtonCell()), CellContentClick, правка, сортировка, режимы выделения, политики ширин, привязка DataSource/DataMember через BindingContext формы (списки, DataTable, таблица DataSet, отношение для мастер-детали; текущая строка и Position источника следуют друг за другом; отношения не становятся столбцами), закреплённые столбцы, виртуальная прокрутка. Свои ячейки (наследник DataGridViewCell с переопределённым Paint) работают и получают унаследованный стиль вместе со шрифтом; стили по умолчанию несут шрифт сетки и следуют за ним, как в WinForms. Правка — по модели WinForms: контрол EditType ячейки (DataGridViewTextBoxEditingControl, DataGridViewComboBoxEditingControl или свой IDataGridViewEditingControl — столбец-календарь из документации Microsoft работает как опубликован) в EditingPanel, EditingControlShowing, «грязная» ячейка и CurrentCellDirtyStateChanged, CellValidating/CellParsing/CellValidated и DataError при фиксации, CellEnter/CellLeave/RowEnter/RowLeave/RowValidating, BeginEdit/EndEdit/CommitEdit/CancelEdit/RefreshEdit, EditMode, ввод/F2/Enter/Escape/Tab; ячейка-флажок правит себя сама (IDataGridViewEditingCell) и фиксируется при уходе, как в WinForms. VirtualMode с RowCount, CellValueNeeded/CellValuePushed, RowDirtyStateNeeded, CancelRowEdit. Строка для новых записей у непривязанной сетки — настоящая строка, как в WinForms: Rows.Count её считает, IsNewRow, Rows.Add вставляет выше неё, Rows.Clear() оставляет новую, ввод в неё добавляет строку (UserAddedRow), вход в неё — DefaultValuesNeeded (в VirtualMode ещё NewRowNeeded); показанная сетка делает текущей первую ячейку. Свойства источника типа Image и byte[] получают столбцы-картинки. Нет: новой строки у привязанной сетки (добавления записей из сетки), копирования в буфер, изменения ширины и порядка столбцов мышью, остальных защищённых Process*Key/On*Changed и методов AutoResize*.
BindingSource ✅ Работает · API: полный Сама реализация WinForms (взята из dotnet/winforms): списки, DataTable, DataSet с таблицей в DataMember, мастер-деталь — второй BindingSource с DataRelation в DataMember, Position, Filter, Sort, AddNew, CurrencyManager.
BindingNavigator ✅ Работает · API полный Реализация WinForms над BindingSource: первая/предыдущая/следующая/последняя, поле позиции (номер и Enter), счётчик (CountItemFormat), добавить и удалить, RefreshItems. В дизайнере появляется со стандартными кнопками, как в VS. Про их картинки — §6.
Сам ADO.NET (DataSet, DataTable, DataAdapter, провайдеры) Часть .NET, а не WinForms: на Linux работает как есть. Правка в привязанной сетке выставляет RowState, поэтому adapter.Update(table) её сохраняет. Платформу определяет провайдер: SQL Server (Microsoft.Data.SqlClient), PostgreSQL, MySQL, SQLite, Firebird, Oracle работают на Linux; Access через System.Data.OleDb — только Windows (на Linux — PlatformNotSupportedException, конвертер предупреждает).
Control.DataBindings, Binding, BindingContext, CurrencyManager ✅ Работает · API: полный Сама реализация WinForms (взята из dotnet/winforms) с её правилами: контрол привязывается, когда он создан и у него есть BindingContext (форма даёт и то и другое); по умолчанию DataSourceUpdateMode.OnValidation — значение уходит в источник при проверке контрола; Format/Parse, FormatString, NullValue, BindingComplete (при включённом форматировании), ErrorProvider над IDataErrorInfo. Дизайнер читает и пишет DataBindings.Add(new Binding(...)) так же, как Visual Studio.
PropertyGrid ✅ Работает · нет 31 Категории, редакторы типов, раскрываемые объекты. Нет: панели команд и её цветов.

Компоненты и диалоги

Компонент Состояние
Timer, ImageList, ErrorProvider, HelpProvider, BackgroundWorker ✅ (HelpProvider: F1 показывает HelpString контрола во всплывающем окне или открывает HelpNamespace на HelpKeyword; в дизайнере добавляет эти свойства всем контролам формы. BackgroundWorker — часть самого .NET и работает как есть)
MessageBox, TaskDialog ✅ Свои диалоги в теме NetForms; надписи на кнопках — на языке интерфейса (английский, русский).
OpenFileDialog, SaveFileDialog, FolderBrowserDialog ✅ Системные диалоги ОС (портал / GTK на Linux). Нет нескольких свойств (ClientGuid, свои места).
ColorDialog, FontDialog ✅ Свои диалоги.
PrintDocument, PrintDialog, PageSetupDialog, PrintPreviewControl, PrintPreviewDialog, PrintControllerWithStatusDialog ✅ Работают · API полный — см. «Печать» в §4. Диалоги — свои формы NetForms (одинаковые в Windows и Linux) с кнопками диалогов Win32 — «Свойства…» (бумага, лоток, ориентация, цвет, двусторонняя печать, качество), «Принтер…» в параметрах страницы, «Справка» — и записывают в PrinterSettings/PageSettings то же, что диалоги Win32. По-английски или по-русски, как интерфейс.
NotifyIcon ✅ См. выше.

4. Подсистемы

Область Состояние
Цикл сообщений Application.Run(Form), Run(ApplicationContext), DoEvents, Exit, Idle, ThreadException (необработанное исключение в обработчике показывает диалог «продолжить/выйти», как в WinForms), IMessageFilter (видит WM_KEYDOWN/WM_KEYUP). ApplicationConfiguration.Initialize() работает. Control.Invoke/BeginInvoke/InvokeAsync передают вызов в UI-поток.
Раскладка Anchor, Dock, Margin/Padding, AutoSize/AutoSizeMode, MinimumSize/MaximumSize, SuspendLayout/ResumeLayout, AutoScroll. Координаты совпадают с настоящим WinForms — это проверяют дифф-тесты при каждой сборке.
Фокус и клавиатура Порядок обхода, TabStop, мнемоники (&Файл), AcceptButton/CancelButton, ProcessCmdKey/ProcessDialogKey/IsInputKey/PreviewKeyDown, оба порядка событий фокуса WinForms (Select() и Focus()), проверка (Validating/Validated, AutoValidate).
Мышь Щелчок, двойной щелчок, захват, колесо, вход/выход/задержка, курсоры (именованные; курсор из файла .cur показывается стрелкой). Cursor.Position можно прочитать, но не задать.
Рисование (System.Drawing) Graphics на SkiaSharp: линии, фигуры, пути, кривые, регионы, отсечение, преобразования, LinearGradientBrush, HatchBrush, TextureBrush, картинки с ImageAttributes/ColorMatrix, LockBits, RotateFlip, значки, ControlPaint. Нет: PathGradientBrush, BufferedGraphics, ImageAnimator (анимированный GIF), метафайлов (Metafile, EMF/WMF); Graphics.CopyFromScreen бросает NotSupportedException. Картинки декодирует Skia (PNG, JPEG, BMP, GIF — первый кадр, ICO, WebP); Image.Save пишет PNG, JPEG и WebP, для BMP и GIF — NotSupportedException.
Текст Эталон — TextRenderer.MeasureText/DrawText (метрики GDI), Graphics.MeasureString/DrawString следуют правилам GDI+. С тем же файлом шрифта числа совпадают с Windows; с заменой (на Linux нет Segoe UI) отличаются на пиксель-два. Зеркалирование RightToLeftLayout не реализовано.
DPI Раскладка идёт в логических пикселях 96 DPI, платформа масштабирует на экран (на HiDPI чётко). AutoScaleMode/AutoScaleDimensions сохраняются; DeviceDpi всегда 96, DpiChanged не возникает.
Тема Одна встроенная светлая тема в духе WinForms с визуальными стилями. Application.SetColorMode(Dark) принимается, тёмная тема пока не рисуется. Типы VisualStyleRenderer есть; рисуют они через тему NetForms.
Ресурсы (.resx) Строки, картинки, значки, типизированные значения, ResXFileRef читаются при выполнении через ComponentResourceManager, как в WinForms. Дизайнер открывает формы с Localizable = true, но пока не записывает их. ImageList.ImageStream (BinaryFormatter в формате дизайнера VS) NetForms читает; прочие ресурсы в BinaryFormatter — нет (см. §2).
Настройки Properties.Settings (ApplicationSettingsBase), ConfigurationManager, app.config компилируются и работают: пакет NetForms приносит System.Configuration.ConfigurationManager, как и среда Windows Desktop.
Буфер обмена Текст ходит через буфер ОС в обе стороны. Картинки, списки файлов, звук и свои форматы — только внутри приложения. DataObject — тот же, что в WinForms (преобразования форматов: Text/UnicodeText/System.String, FileDrop/FileNameW, Bitmap; SetDataAsJson/TryGetData<T> из .NET 9+).
Перетаскивание ✅ Протокол OLE, который ведёт сам NetForms: DoDragDrop модальный и возвращает эффект; источник получает QueryContinueDrag (Escape отменяет, отпускание кнопки бросает) и GiveFeedback (стандартные курсоры, если он не рисует свои); контрол под указателем с AllowDrop — или ближайший родитель с ним, как OLE ищет зарегистрированное окно, — получает DragEnter/DragOver/DragLeave/DragDrop с экранными X/Y, KeyState и Effect в точности как в WinForms. Перетаскивание переходит между формами приложения. Бросок из других программ (файлы из файлового менеджера, текст) приходит через платформу как FileDrop/Text. Пока нет: перетаскивания наружу в другую программу, картинки перетаскивания в DoDragDrop(…, dragImage, …), RichTextBox.EnableAutoDragDrop.
IME Готовый текст от методов ввода (китайский, японский, корейский…) приходит в KeyPress/TextBox. Строку набора показывает окно самого метода ввода, не сам контрол.
Специальные возможности 🟡 Модель: AccessibleObject, Control.ControlAccessibleObject, AccessibilityObject/CreateAccessibilityInstance (свои контролы описывают себя, как в WinForms), AccessibleRole, имена из текста или из подписи перед контролом, сочетания клавиш из мнемоник, состояния, границы, дети, DoDefaultAction, QueryAccessibilityHelp. Пока нет моста в ОС (UI Automation / AT-SPI через automation peers Avalonia) — экранные дикторы контролы NetForms пока не видят.
Печать ✅ System.Drawing.Printing полностью: PrintDocument с циклом страниц и событиями WinForms, PageSettings/PrinterSettings с форматами бумаги, лотками, разрешениями, двусторонней печатью, цветом и физическими полями принтера, Margins, PrinterUnitConvert, QueryPageSettings для каждой страницы (вперемешку с альбомными), OriginAtMargins, отмена из BeginPrint/PrintPage. Graphics страницы работает в 1/100 дюйма, текст — физического размера, DpiX — принтера. Linux/macOS: принтеры и их параметры — из CUPS (lpstat, lpoptions), задание — PDF, отданный lp с копиями, разбором по копиям, двусторонней печатью и цветом. Windows: winspool и драйвер (DeviceCapabilities, DEVMODE), задание идёт через GDI (каждая страница рисуется Skia до 300 dpi). Печать в файл пишет PDF. Предпросмотр (PrintPreviewControl/Dialog) хранит страницы векторно и чётко показывает при любом масштабе; работает и без принтеров. GetHdevmode/SetHdevmode/GetHdevnames отдают блоки DEVMODE/DEVNAMES в формате Win32.
Справка Help.ShowHelp открывает файлы и URL системной программой; F1 вызывает HelpRequested. Просмотрщики CHM есть только в Windows.
Звук System.Media.SoundPlayer — часть .NET и там только для Windows; NetForms своего не добавляет.

5. API только для Windows

У контролов NetForms нет собственного окна ОС (нет HWND). Всё, что его предполагает, компилируется, но ничего не делает, или отсутствует:

API В NetForms
Control.Handle, Form.Handle, ImageList.Handle IntPtr.Zero. IsHandleCreated, HandleCreated, HandleDestroyed следуют жизненному циклу WinForms.
WndProc, DefWndProc, CreateParams, CreateHandle, FromHandle, NativeWindow Переопределения компилируются; платформа их не вызывает, сообщения не синтезируются. NativeWindow нет.
P/Invoke в user32, gdi32, comctl32, uxtheme, dwmapi, shell32… На Linux — DllNotFoundException (в Windows работает, но передаваемые дескрипторы — нули). Конвертер перечисляет каждый такой вызов с файлом и строкой.
Microsoft.Win32.Registry, Application.UserAppDataRegistry Реестр в .NET есть только в Windows; UserAppDataRegistry нет. Конвертер предупреждает.
ActiveX (AxHost), COM, WebBrowser, WebView2, CefSharp Нет и не планируется.
SendKeys, InputLanguage, SystemEvents, состояние питания Нет.
Screen Настоящие мониторы от платформы; SystemInformation отдаёт то, чем рисует NetForms, остальное — значения Windows 10/11 по умолчанию.

6. Осознанные отличия

Отличия, которые известны, измерены и оставлены сознательно. Всё остальное, что отличается от WinForms, — ошибка; пожалуйста, сообщите о ней.

  • Внешний вид. Контролы выглядят как WinForms с визуальными стилями, но рисует их NetForms, а не uxtheme, — попиксельного совпадения с Windows не добиваемся. Вид одинаков на Windows и Linux.
  • Пути в стиле Windows в файловых API NetForms. Image.FromFile, new Bitmap(path), new Icon(path), Image.Save, PrivateFontCollection.AddFontFile на Linux понимают \ и не различают регистр, если точного имени нет, — так продолжает работать Application.StartupPath + @"\img\x.png". System.IO.File так не умеет; конвертер предупреждает о таких строках.
  • Выпадающие меню примерно на 10 px уже: колонка картинок рисуется под элементами, а не в отступе.
  • NotifyIcon: оболочки Linux сообщают только о щелчке основной кнопкой, поэтому двойной щелчок синтезируется, события правой кнопки приходят только при открытии меню, MouseMove не приходит, меню рисует оболочка.
  • Значки ErrorProvider не мигают.
  • DataGridView: необработанный DataError не показывается окном сообщения (WinForms показывает); у привязанной сетки пока нет строки для новых записей (в WinForms есть, когда список разрешает добавление); назначенный DefaultCellStyle с незаданными членами дозаполняется сам (WinForms отдаёт из геттера заполненную копию).
  • Form.TopLevel = false: у встроенной формы нет рамки (WinForms её рисует).
  • RichTextBox.Rtf записывает не-ASCII символы как \uN? (RichEdit — как \'hh в кодовой странице шрифта); читаются оба варианта.
  • Отрицательные размеры докнутого контрола без родителя сразу обрезаются до 0 (WinForms делает это при создании окна).
  • Печать: PreviewPageInfo.Image — Bitmap (в WinForms — EMF Metafile, которого в NetForms нет); предпросмотру не нужен принтер (WinForms без него бросает InvalidPrinterException); печать в файл пишет PDF (WinForms — то, что выдаёт драйвер); IsDirectPrintingSupported всегда false; в Windows страницы уходят драйверу картинками (не больше 300 dpi), а не командами GDI.
  • BindingNavigator в дизайнере NetForms: картинки стандартных кнопок не пишутся в код формы (Visual Studio кладёт их в .resx, который дизайнер пока не пишет); навигатор возвращает их сам, если у стандартной кнопки, показывающей только картинку, её нет. Форма из Visual Studio сохраняет свои картинки из .resx.
  • Сохранение картинок: Image.Save пишет BMP, GIF, TIFF, PNG, JPEG и WEBP; GIF — с постоянной палитрой из 252 цветов (GDI+ — со своей полутоновой); Icon, EMF, WMF, Exif и HEIF сохраняются как PNG — как в GDI+, где для них нет кодировщика.
  • Перетаскивание внутри приложения идёт мимо ОС (протокол ведёт NetForms), поэтому вытащить что-то наружу из приложения пока нельзя, а картинка перетаскивания из DoDragDrop не рисуется.
  • Системные цвета: SystemColors.* на Linux — собственная таблица .NET (классическая палитра Windows), в Windows — палитра ОС. Тема NetForms всегда рисует светлой палитрой Windows 10/11.

7. Как измеряется совместимость

  • Дифф-тесты против настоящего WinForms (tests/NetForms.Compat, CI на Windows): одни и те же сценарии выполняются в System.Windows.Forms и в NetForms; сравниваются положения, размеры, порядок событий, метрики текста, атрибуты времени разработки и то, что записывает дизайнер. Набор — 641/641; в CI на Windows он идёт со всеми тремя оракулами настоящего WinForms.
  • Golden-тесты отрисовки (без окна, одинаковые картинки на Windows и Linux).
  • Покрытие API — dotnet run --project tools/NetForms.ApiDiff -- --markdown docs/api заново строит таблицы. Сейчас: 761 из 1254 типов полные, 141 частично, 352 нет (в основном EventArgs, accessible-объекты отдельных контролов и удалённые контролы 1.x).
  • Корпус реальных проектов (NETFORMS_CORPUS=1, задача CI corpus): проекты переводятся и собираются без ручных правок, причина каждого провала записана в tests/corpus/corpus.json.

8. Что дальше

Что добавлять первым, решает код, который пишут люди, а не длина списка: NetForms.ApiDiff --usage компилирует каждый проект корпуса против настоящего WinForms и считает каждое обращение к типу или члену, которого в NetForms нет, — недостающий API по использованию (на английском). Из 25 887 обращений к API WinForms в 63 проектах (24 репозитория) недостающих не осталось: последние (ImageFormat.Icon/Tiff/Wmf, ImageList.Images.Add(string, Icon), LinkLabel.OverrideCursor, OpenFileDialog.SafeFileName, TabPages.Remove, конструктор Font с набором символов) добавлены в 0.1.0-preview.8 (решение 166), и MDBEditor, GetStockIcon и библиотека xrails-login-ui теперь собираются.

Дальше порядок задаёт более широкая выборка открытого кода на WinForms — ему достаточно компилироваться против настоящего WinForms, а не собираться с NetForms. Из известного заранее: экранные дикторы (модель доступности уже есть), перетаскивание за пределы приложения, тёмная тема, .resx в дизайнере (картинки, локализуемые формы).

Исправить страницу на GitHub