NetForms

Библиотеки элементов управления в дизайнере

Панель элементов дизайнера не ограничена контролами NetForms. На ней есть собственные контролы вашего проекта и контролы любой библиотеки, на которую он ссылается, — пакета NuGet, .dll, другого проекта решения. На холсте они настоящие: их конструкторы выполняются, они рисуют себя сами, а панель свойств и вкладка событий показывают их собственные свойства и события.

Эта страница — практическое руководство. Как это устроено внутри — designer-control-libraries.md.

Собственные контролы проекта

Ничего делать не нужно. Напишите контрол в проекте —

namespace Shop.Controls;

public class StarRating : Control
{
    [DefaultValue(3), Category("Appearance"), Description("How many stars are lit.")]
    public int Stars { get; set; } = 3;

    protected override void OnPaint(PaintEventArgs e)
    {
        for (int i = 0; i < Stars; i++) e.Graphics.FillEllipse(Brushes.Gold, i * 20, 0, 18, 18);
    }
}

— соберите проект (dotnet build, F5, NetForms: Rescan Toolbox или ↻ вверху панели элементов), и он появится в группе Shop Components в начале панели, как в Visual Studio. В группе — все открытые контролы, пользовательские контролы и компоненты проекта; формы не показываются (их проектируют, а не перетаскивают).

Дизайнер работает с последней успешной сборкой. Поменяйте контрол и соберите снова — открытые формы подхватят новую версию сами, без перезапуска. Контрол, написанный после последней сборки, до следующей показывается пунктирной заглушкой с именем типа; из формы при этом ничего не теряется.

Форма может наследовать форму проекта (public partial class OrderForm : BaseForm): на холсте видно то, что кладёт на неё базовая форма, как в Visual Studio.

Своя группа для папки. Если контролов много, дайте папке отдельную группу: NetForms: Add Control Library… → Папка этого проекта…, выберите Controls/Charts, назовите группу. Контролы пространства имён этой папки (Shop.Controls.Charts) переедут из Shop Components в новую группу.

Как подключить библиотеку

NetForms: Add Control Library… — из палитры команд, кнопкой + Библиотека элементов… на панели элементов или из контекстного меню .csproj в проводнике. Само ничего не ставится — ни при открытии формы, ни при перетаскивании: библиотека попадает в проект только этой командой.

Источник Что вы делаете Что меняется в проекте
Пакет NuGet… Вводите название — поиск по nuget.org идёт по мере ввода, — затем выбираете версию (первой стоит последняя стабильная). Пакет скачивается во временную папку и сначала проверяется. Затем dotnet add package.
Файл .dll… Выбираете файл. В .csproj добавляется <Reference> с <HintPath>. Файл вне проекта дизайнер предложит скопировать в libs/ (вместе с .pdb и .xml) — соглашайтесь, иначе на другой машине проект не соберётся.
.nupkg или папка-фид… Выбираете .nupkg или папку с ними, затем пакет. Собственные и корпоративные пакеты. Папка становится источником пакетов в nuget.config проекта (он создаётся — вместе с nuget.org, — если его нет), дальше — как пакет NuGet. Дизайнер ещё раз спросит: пакет не с nuget.org.
Папка этого проекта… Выбираете папку, называете группу. Ничего: см. выше.
Другой проект… Выбираете .csproj рабочей области (или «Обзор…»). dotnet add reference. Его контролы обновляются вслед за его сборками: пересоберите только тот проект — дизайнер возьмёт его свежий результат.
Пакет NuGet, уже подключённый к проекту… Отмечаете пакеты, которые показывать. Ничего: пакеты берутся из obj/project.assets.json (то, что разрешил dotnet restore), в том числе подключённые другими пакетами.

После проверки дизайнер покажет найденные контролы и компоненты — с иконками из [ToolboxBitmap], — все с галочками. Снимите галочки с того, что не нужно на панели. Затем проект собирается, и группа библиотеки появляется на панели элементов всех открытых дизайнеров этого проекта.

Библиотеки, добавленные раньше в любом проекте, предлагаются первыми (Недавние): один выбор — и пакет или .dll уже в новом проекте и на его панели.

Зависимости, версии, нативные части, конфликты — работа MSBuild и NuGet, ровно как при запуске приложения: дизайнер загружает результат сборки проекта вместе с его .deps.json.

Что говорит проверка

Перед добавлением сборки библиотеки читаются без выполнения её кода (только метаданные):

Библиотека Дизайнер
собрана под NetForms (ссылается на пакет NetForms) ✅ добавляет
собрана под настоящий System.Windows.Forms ⚠️ спрашивает: показать её контролы дизайнер может (фасад NetForms перенаправляет System.Windows.Forms), но проект с ней может не скомпилироваться — CS0012, строгое имя System.Windows.Forms, — и скорее всего не соберётся на Linux. См. Совместимость § сторонние пакеты.
пакет, у которого нативные части только в runtimes/win-* ⚠️ спрашивает: на Linux её контролы работать не будут
пакет только для net*-windows ⚠️ спрашивает: проекту нужен целевой фреймворк Windows
собрана под .NET Framework (net48…), под .NET новее 10 или вовсе не сборка .NET ❌ не добавляется, с объяснением

У пакета проверяется та папка lib/, которую возьмёт проект net10.0: net10.0, иначе ближайшая более старая netX.0, netcoreapp3.1, netstandard2.1, netstandard2.0.

Тип попадает на панель, как в Visual Studio: открытый, не абстрактный, не обобщённый компонент (IComponent) с открытым конструктором без параметров, без [ToolboxItem(false)] и [DesignTimeVisible(false)] (на нём самом или на базовом классе), и не форма. Компоненты без места на форме (как Timer) уходят в лоток.

Как убрать библиотеку и пересканировать

NetForms: Remove Control Library — выберите библиотеку, затем Только с панели элементов (ссылка в проекте остаётся, он по-прежнему собирается с ней) или С панели элементов и из проекта (dotnet remove package / dotnet remove reference или <Reference> удаляется из .csproj; .dll в libs/ остаётся на диске). Формы, где стоят её контролы, сохраняют их — заглушками, которые хранят каждую строку своего кода.

NetForms: Rescan Toolbox (↻ на панели) собирает проект и заново читает его контролы и библиотеки. Дизайнер делает это и сам — после каждой замеченной сборки и после изменения .csproj или .vscode/netforms.json.

Где это хранится: .vscode/netforms.json

Ссылки лежат там, где их читает MSBuild, — в .csproj. Что показывает панель элементов — в .vscode/netforms.json рабочей папки, по проектам. Закоммитьте его — у коллег будет та же панель.

{
	"projects": {
		"src/Shop/Shop.csproj": {
			"libraries": [
				{
					"id": "package:scottplot.winforms",
					"name": "ScottPlot.WinForms",
					"source": "package",
					"package": "ScottPlot.WinForms",
					"version": "5.0.47",
					"assemblies": ["ScottPlot.WinForms.dll"],
					"types": ["ScottPlot.WinForms.FormsPlot"]
				},
				{
					"id": "folder:controls/charts",
					"name": "Charts",
					"source": "folder",
					"path": "Controls/Charts",
					"namespace": "Shop.Controls.Charts",
					"assemblies": []
				}
			]
		}
	}
}
Поле
name Группа на панели элементов. Можно менять.
source package, dll, feed, folder, projectReference или projectPackage (пакет, уже подключённый к проекту).
assemblies Файлы сборок библиотеки; ищутся в результате сборки проекта (пакет библиотеки классов, который туда не копируется, берётся из кэша NuGet).
types Показываются только эти типы; без поля — всё, что предлагает библиотека.
projectComponents: false (у проекта, рядом с libraries) скрывает автоматическую группу <Проект> Components.

Библиотека, ссылка на которую пропала из .csproj (удалена руками, переключена ветка), просто не показывается — дизайнер от этого не ломается.

Попробовать: NetForms.ExtraControls

NetForms.ExtraControls — библиотека контролов на nuget.org от самого проекта NetForms; на ней быстрее всего увидеть, как пакет попадает на панель элементов:

  1. Откройте форму проекта NetForms в дизайнере.
  2. NetForms: Add Control Library… → NuGet package…, введите NetForms.ExtraControls, выберите последнюю версию.
  3. Проверка скажет ✅ собрана под NetForms и покажет шесть элементов со значками: ToggleSwitch, RatingStars, CircularProgressBar, GradientPanel, ColorPickerButton и CountdownTimer. Оставьте галочки.
  4. Проект собирается, на панели элементов появляется группа NetForms.ExtraControls. Перетащите на форму GradientPanel, в неё — ToggleSwitch; CountdownTimer уйдёт в лоток компонентов и запишется как new CountdownTimer(components).
  5. В окне свойств — их собственные категории и описания (Checked, OnColor, Duration…), на вкладке событий — их события (CheckedChanged, Finished…).

Из командной строки: dotnet add package NetForms.ExtraControls. Её исходники — src/NetForms.ExtraControls в репозитории — полный пример для следующего раздела: атрибуты, значки, контейнер, компонент для лотка.

Как написать библиотеку контролов для NetForms

Библиотека контролов — это библиотека классов со ссылкой на NetForms:

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>net10.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
  </PropertyGroup>
  <ItemGroup>
    <PackageReference Include="NetForms" Version="0.1.5" />
    <Using Include="System.Drawing" />
    <Using Include="System.Windows.Forms" />
  </ItemGroup>
  <ItemGroup>
    <!-- Иконка панели элементов: 16×16, цвет левого нижнего пикселя — прозрачный. -->
    <EmbeddedResource Include="Gauge.bmp" LogicalName="MyControls.Gauge.bmp" />
  </ItemGroup>
</Project>

Дизайнер читает те же метаданные System.ComponentModel, что и Visual Studio:

Атрибут В дизайнере
[ToolboxBitmap(typeof(Gauge), "Gauge.bmp")] Иконка на панели элементов (ресурс Namespace.Gauge.bmp находится и без атрибута).
[ToolboxItem(false)], [DesignTimeVisible(false)] Не показывать на панели.
[DefaultValue], ShouldSerializeX()/ResetX() Что пишется в *.Designer.cs; значение, отличное от умолчания, в панели свойств жирное.
[Category], [Description], [Browsable(false)] Панель свойств.
[DefaultEvent] Что подключает двойной щелчок по контролу.
[TypeConverter] Как значение показывается и вводится в панели свойств.
[DesignerSerializationVisibility(Content)] Коллекция или объект пишется своим содержимым.

На холсте Site.DesignMode равен true, как на поверхности дизайна Visual Studio: таймеры, сеть и базы данных там лучше не трогать. Собственные дизайнеры ([Designer], смарт-теги) и UITypeEditor пока не используются — панель свойств редактирует значение текстом через его TypeConverter.

Упакуйте (dotnet pack) и подключите .nupkg через .nupkg или папка-фид… или опубликуйте на nuget.org.

Безопасность: доверие к рабочей области

Код библиотеки выполняется в процессе хоста дизайнера — её конструкторы, сеттеры свойств и OnPaint, — как и в Visual Studio. Поэтому:

  • В папке, которой VS Code не доверяет (ограниченный режим), панель показывает контролы проекта только по метаданным, серыми: их код не загружается, а Add Control Library недоступна. Доверьтесь папке — и они оживут.
  • Пакет не с nuget.org (.nupkg, локальный фид) перед добавлением подтверждается ещё раз.
  • Контрол, у которого бросает исключение конструктор или OnPaint, рисуется красным крестом с текстом исключения (так WinForms рисует контрол, отрисовка которого упала). Форма всё равно открывается, и каждая строка кода этого контрола сохраняется.
  • Хост работает в отдельном процессе: что бы ни сделал контрол, VS Code вместе с ним не упадёт.
  • Сборки загружаются из копии, поэтому следующий dotnet build не упрётся в занятую .dll.

Неполадки

Что видно Почему и что делать
На панели — Соберите проект, чтобы увидеть здесь его элементы управления Проект ещё не собирался (нет bin/…/<Проект>.dll). Нажмите ↻ или выполните dotnet build.
Контрол на холсте — пунктирная рамка с именем типа Его типа нет в последней сборке (написан позже или сборка упала), либо на библиотеку нет ссылки. Соберите проект; ошибки компилятора — в выводе NetForms.
Красный крест с исключением Конструктор или OnPaint контрола бросил исключение на холсте. Оградите код, не нужный при проектировании: if (DesignMode) return; или Site?.DesignMode.
Элементы библиотеки серые Ограниченный режим (доверьтесь папке) или загруженная сборка старше библиотеки (соберите снова). Подсказка при наведении скажет причину.
При добавлении — …нельзя использовать в дизайнере См. Что говорит проверка: обычно библиотека только для .NET Framework.
Поиск по nuget.org ничего не находит Поиск nuget.org недоступен (прокси, закрытая сеть): введите точный идентификатор пакета и нажмите Enter; версии берутся с api.nuget.org. В закрытой сети используйте локальный фид.
После добавления пакета WinForms проект не собирается CS0012 про System.Windows.Forms: пакет собран под настоящий WinForms — см. Совместимость. Уберите его: Remove Control Library → С панели элементов и из проекта.

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