Управляемые формы 1С требуют иного мышления, чем обычные: нет модальности, данные живут то на клиенте, то на сервере, а результат из открытой формы возвращается через оповещение. Ниже собрал четыре приёма, которые закрывают типовые задачи: своё представление объекта в полях и списках, ввод значений без создания отдельной формы, сообщения пользователю, которые не теряются при закрытии окна, и оповещение о закрытии, которое не срабатывает, если форма закрывается в ПриОткрытии.

Каждый приём самостоятельный, код можно переносить в расширение конфигурации, не меняя типовые модули.

Своё представление объекта в 1С

По умолчанию справочник показывается наименованием, документ — «Название № номер от даты». Если хочется видеть в поле ввода и в списках, например, сумму и валюту, представление переопределяется в модуле менеджера двумя обработчиками.

1С
// Состав полей, которые платформа прочитает для построения представления.
Процедура ОбработкаПолученияПолейПредставления(Поля, СтандартнаяОбработка)

	СтандартнаяОбработка = Ложь;
	Поля.Добавить("Номер");
	Поля.Добавить("Дата");
	Поля.Добавить("СуммаДокумента");
	Поля.Добавить("Валюта");

КонецПроцедуры

// Формирование строки представления из прочитанных полей.
Процедура ОбработкаПолученияПредставления(Данные, Представление, СтандартнаяОбработка)

	СтандартнаяОбработка = Ложь;
	Представление = СтрШаблон(НСтр("ru = 'Счет № %1 от %2 на %3 %4'"),
		Данные.Номер,
		Формат(Данные.Дата, "ДЛФ=D"),
		Формат(Данные.СуммаДокумента, "ЧДЦ=2; ЧН=0"),
		Данные.Валюта);

КонецПроцедуры

Как это работает: платформа сначала спрашивает, какие поля нужны (Поля), читает их одним запросом и передаёт в Данные. Поэтому в ОбработкаПолученияПредставления нельзя обращаться к реквизитам, которых нет в Поля, и не стоит делать запросы — обработчик вызывается очень часто: в каждом поле, в каждой строке списка.

Рекомендации из практики:

  • держите представление коротким — оно же выводится в заголовках форм и сообщениях;
  • не меняйте представление «под один отчёт»: оно глобально для всей базы;
  • в типовой конфигурации делайте это в расширении, в модуле менеджера объекта расширения.

Ввод значений без отдельной формы: всплывающая группа

Задача: по кнопке показать пользователю несколько полей или табличную часть для заполнения, как будто открылось отдельное окно, но без новой формы и без описания передачи данных туда и обратно.

Классический путь — отдельная форма с реквизитами, параметрами открытия и возвратом результата через Закрыть(Результат). Альтернатива — обычная группа на текущей форме с поведением «Всплывающая». В неё кладутся нужные поля и кнопка «Готово», а сама группа по умолчанию скрыта (Видимость = Ложь).

1С
&НаКлиенте
Процедура ОткрытьВводЗначений(Команда)

	Элементы.ГруппаВводЗначений.Видимость = Истина;
	// Сразу после установки видимости Показать() не срабатывает - откладываем
	ПодключитьОбработчикОжидания("ПоказатьГруппуВвода", 0.1, Истина);
	// Следим за закрытием «крестиком», чтобы снова скрыть группу
	ПодключитьОбработчикОжидания("ПроверитьЗакрытиеГруппыВвода", 1);

КонецПроцедуры

&НаКлиенте
Процедура ПоказатьГруппуВвода()
	Элементы.ГруппаВводЗначений.Показать();
КонецПроцедуры

&НаКлиенте
Процедура ПроверитьЗакрытиеГруппыВвода()

	Если Элементы.ГруппаВводЗначений.Скрыта() Тогда
		Элементы.ГруппаВводЗначений.Видимость = Ложь;
		ОтключитьОбработчикОжидания("ПроверитьЗакрытиеГруппыВвода");
	КонецЕсли;

КонецПроцедуры

&НаКлиенте
Процедура ЗавершитьВводЗначений(Команда)

	Элементы.ГруппаВводЗначений.Скрыть();
	Элементы.ГруппаВводЗначений.Видимость = Ложь;
	ОтключитьОбработчикОжидания("ПроверитьЗакрытиеГруппыВвода");

КонецПроцедуры

Плюсы: поля привязаны прямо к Объект, ничего не нужно передавать и возвращать. Минусы: окно нельзя масштабировать и выбрать режим открытия, логику открытия-закрытия приходится имитировать обработчиками ожидания. Я применяю этот приём для двух-трёх полей «быстрого ввода»; если полей больше или нужна проверка заполнения — делаю нормальную форму.

Сообщения пользователю, которые не пропадают после закрытия формы

Типичная жалоба: при «Провести и закрыть» сервер выводит предупреждение, но пользователь его не видит. Причина в том, что сообщения с сервера (СообщениеПользователю.Сообщить() или ОбщегоНазначения.СообщитьПользователю() из БСП) не выводятся сразу, а копятся и показываются в окне формы при возврате на клиент. Форма тут же закрывается — и сообщения вместе с ней.

Решение: на сервере, в последнем вызове перед возвратом, забрать сообщения функцией ПолучитьСообщенияПользователю(), сохранить их в реквизите формы и заново вывести в клиентском ПриЗакрытии. В момент ПриЗакрытии форма уже закрыта, и сообщения попадут в активное окно или в нижнюю панель приложения.

Управляемые формы 1С: сообщения сервера сохраняются и выводятся после закрытия окна
Управляемые формы 1С: сообщения сервера сохраняются и выводятся после закрытия окна

Реквизит формы СообщенияСервера с типом «Произвольный» добавьте в форму (или в форму в расширении). Дальше код:

1С
&НаСервере
Процедура ПослеЗаписиНаСервере(ТекущийОбъект, ПараметрыЗаписи)

	// Ложь - не удаляем сообщения из очереди: если форма не закроется,
	// они штатно выведутся в неё, а ПриЗакрытии не сработает и дубля не будет
	Сообщения = ПолучитьСообщенияПользователю(Ложь);

	Сохраненные = Новый Массив;
	Для Каждого Сообщение Из Сообщения Цикл
		Сохраненные.Добавить(Новый ФиксированнаяСтруктура("Текст, КлючДанных, Поле, ПутьКДанным",
			Сообщение.Текст, Сообщение.КлючДанных, Сообщение.Поле, Сообщение.ПутьКДанным));
	КонецЦикла;
	СообщенияСервера = Новый ФиксированныйМассив(Сохраненные);

КонецПроцедуры

&НаКлиенте
Процедура ПриЗакрытии(ЗавершениеРаботы)

	Если ЗавершениеРаботы Или СообщенияСервера = Неопределено Тогда
		Возврат;
	КонецЕсли;

	Для Каждого Сообщение Из СообщенияСервера Цикл
		ОбщегоНазначенияКлиент.СообщитьПользователю(Сообщение.Текст, Сообщение.КлючДанных,
			Сообщение.Поле, Сообщение.ПутьКДанным);
	КонецЦикла;

КонецПроцедуры

Сообщения я переупаковываю в фиксированные структуры, чтобы в реквизите формы лежали простые сериализуемые значения. Параметр Ложь выбран намеренно: при Истина сообщения удаляются из очереди, и если форма не закрылась, выводить их придётся вручную. При Ложь в обычном сценарии работает штатный вывод, а наш код страхует только закрытие.

Если запись идёт не через форму объекта, а через свою серверную функцию, забирайте сообщения в конце этой функции.

Не срабатывает оповещение о закрытии формы

Результат из формы обычно возвращают через ОписаниеОповещенияОЗакрытии:

1С
&НаКлиенте
Процедура ОтгрузитьЗаказ(Команда)

	ПараметрыФормы = Новый Структура("Ключ", ТекущийЗаказ);
	Оповещение = Новый ОписаниеОповещения("ОтгрузитьЗаказЗавершение", ЭтотОбъект);
	ОткрытьФорму("Документ.ЗаказКлиента.ФормаОбъекта", ПараметрыФормы, ЭтотОбъект, , , ,
		Оповещение, РежимОткрытияОкнаФормы.БлокироватьОкноВладельца);

КонецПроцедуры

&НаКлиенте
Процедура ОтгрузитьЗаказЗавершение(Результат, ДополнительныеПараметры) Экспорт

	Если Результат = Неопределено Тогда
		Возврат;
	КонецЕсли;
	ОбработатьВыбранныйЗаказ(Результат);

КонецПроцедуры

В открываемой форме результат передаётся через Закрыть(Результат). Это работает, пока форма успела открыться. Но если форма решает закрыться сразу — например, в ПриОткрытии выясняется, что выбор не нужен, — вызов Закрыть() в ПриОткрытии оповещение не вызывает. Вызывающая форма так и не узнает результат.

Способ 1: отложенное закрытие

1С
&НаКлиенте
Процедура ПриОткрытии(Отказ)
	Если ВыборНеТребуется Тогда
		ПодключитьОбработчикОжидания("ЗакрытьСРезультатом", 0.1, Истина);
	КонецЕсли;
КонецПроцедуры

&НаКлиенте
Процедура ЗакрытьСРезультатом()
	Закрыть(ТекущийЗаказ);
КонецПроцедуры

Работает, но форма на мгновение появляется на экране и мигает. Если в ней тяжёлая инициализация, пользователь это заметит.

Способ 2: отказ от открытия и ручной вызов оповещения

У формы есть свойство ОписаниеОповещенияОЗакрытии — то самое описание, переданное в ОткрытьФорму. Его можно выполнить вручную и отменить открытие:

1С
&НаКлиенте
Процедура ПриОткрытии(Отказ)

	Если ВыборНеТребуется Тогда
		Отказ = Истина;
		Если ОписаниеОповещенияОЗакрытии <> Неопределено Тогда
			ВыполнитьОбработкуОповещения(ОписаниеОповещенияОЗакрытии, ТекущийЗаказ);
		КонецЕсли;
	КонецЕсли;

КонецПроцедуры

Пользователь не видит окна, а вызывающая форма получает результат как обычно. Проверка на Неопределено нужна, если форму могут открыть и без оповещения.

Управляемые формы 1С: форма не открывается, а результат сразу передаётся вызывающему окну
Управляемые формы 1С: форма не открывается, а результат сразу передаётся вызывающему окну

Ещё лучше — если условие можно проверить до открытия: тогда вызывающий код вообще не открывает форму. Приём со ВыполнитьОбработкуОповещения нужен, когда решение принимает именно открываемая форма.

Какой приём когда применять

СитуацияПриёмНа что обратить внимание
Ссылка в полях и списках выглядит неинформативноСвоё представление в модуле менеджераДействует на всю базу, без запросов внутри
Нужно ввести 2–3 значения по кнопкеВсплывающая группаДля сложного ввода лучше отдельная форма
Предупреждения сервера теряются при закрытииПолучитьСообщенияПользователю + ПриЗакрытииПараметр Ложь, чтобы не было дублей
Форма должна закрыться сразу при открытии и вернуть результатОтказ + ВыполнитьОбработкуОповещенияЛучше вообще не открывать форму, если условие известно заранее

Все четыре приёма хорошо ложатся в расширение: обработчики модуля менеджера, события формы и новые реквизиты формы добавляются без изменения типовой конфигурации. Если в типовом обработчике формы уже есть код, используйте аннотацию &После для событий формы, чтобы не перекрывать типовую логику.

Типичные ошибки

  • Запросы в ОбработкаПолученияПредставления. Каждая строка списка превращается в отдельный запрос, список начинает тормозить.
  • Поле не перечислено в Поля. Обращение к Данные.Реквизит даст ошибку.
  • ПолучитьСообщенияПользователю(Истина) без вывода. Сообщения удалены и никуда не выведены.
  • Неэкспортный обработчик оповещения. Платформа не сможет его вызвать.
  • Закрытие в ПриОткрытии через Закрыть(). Результат теряется — используйте Отказ и ручной вызов оповещения.
Большинство «странностей» управляемых форм объясняется тем, где и когда выполняется код: на клиенте или на сервере, до открытия окна или после.

Такие доработки форм в типовых конфигурациях делаю через расширения 1С, чтобы обновления проходили без конфликтов; более крупные изменения интерфейса — в рамках доработки 1С.

Итог

  • Своё представление объекта задаётся в модуле менеджера: ОбработкаПолученияПолейПредставления + ОбработкаПолученияПредставления.
  • Для пары полей быстрого ввода хватает всплывающей группы на текущей форме.
  • Серверные сообщения при закрытии формы сохраняйте через ПолучитьСообщенияПользователю(Ложь) и выводите в ПриЗакрытии.
  • Если форма должна закрыться сразу при открытии, ставьте Отказ = Истина и вызывайте ВыполнитьОбработкуОповещения(ОписаниеОповещенияОЗакрытии, Результат).