Диалоги в 1С 8.3: вопросы, предупреждения и собственные формы

· 9 мин

Содержание

Диалог в 1С 8.3 начинается с одной строки: Предупреждение("Сохранено") покажет окно с кнопкой ОК, а Вопрос("Провести документ?", РежимДиалогаВопрос.ДаНет) вернёт выбор пользователя. Это встроенные методы, писать форму под них не нужно.

Сложнее, когда простого «да/нет» не хватает — нужно ввести несколько значений, показать таблицу, вернуть результат в вызвавший код. Тогда делают собственную управляемую форму и открывают её через ОткрытьФорму.

Ниже — оба подхода: системные диалоги, свои формы, передача параметров туда и обратно, управление элементами на лету и асинхронные вызовы, без которых в современной платформе модальные окна просто не запустятся.

Системные диалоги: вопрос, предупреждение, сообщение

Три базовых инструмента доступны без всякой формы — в любом клиентском модуле.

🔹 Предупреждение — показывает текст и одну кнопку ОК, ничего не возвращает:

Предупреждение("Документ проведён");

🔹 Вопрос — показывает набор кнопок и возвращает выбранную:

Ответ = Вопрос("Удалить строку?", РежимДиалогаВопрос.ДаНет);
Если Ответ = КодВозвратаДиалога.Да Тогда
    УдалитьСтроку();
КонецЕсли;

Набор кнопок задаёт РежимДиалогаВопрос: ДаНет, ДаНетОтмена, ОКОтмена, ПовторитьОтмена, ПрерватьПовторитьПропустить. Результат сравнивают со значениями КодВозвратаДиалога — Да, Нет, ОК, Отмена, Повторить, Прервать, Пропустить, Таймаут.

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

Сообщение = Новый СообщениеПользователю;
Сообщение.Текст = "Заполните контрагента";
Сообщение.Поле = "Объект.Контрагент";
Сообщение.Сообщить();

Отдельно стоит выбор из списка. Когда вариантов несколько, не городите цепочку вопросов — покажите список значений:

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

Обработчик получит выбранный элемент списка (или Неопределено, если пользователь отменил выбор). Для выпадающего меню у кнопки есть близкий метод ПоказатьВыборИзМеню.

Вопрос и Предупреждение — модальные: код останавливается и ждёт пользователя. В платформе 8.3 с выключенной модальностью они не запустятся напрямую — об этом раздел об асинхронности.

Своя форма как диалог: открываем через ОткрытьФорму

Когда нужно больше, чем кнопки, — ввести дату, выбрать из списка, заполнить реквизиты — создают управляемую форму и открывают её как отдельное окно.

Сначала форму создают в конфигураторе. Для диалога, не привязанного к конкретному объекту, удобна общая форма:

  1. В дереве конфигурации правой кнопкой на ветке Общие → Общие формы → Добавить.
  2. Задайте имя (например, ВводПараметров) — по нему форма вызывается из кода.
  3. На закладке Реквизиты добавьте реквизиты формы под вводимые значения.
  4. Перетащите реквизиты в дерево элементов, добавьте кнопки ОК и Отмена.

После этого форму вызывают по полному имени ОбщаяФорма.<Имя>:

ОткрытьФорму("ОбщаяФорма.ВводПараметров");

Для формы объекта или обработки имя строят так же: Обработка.ЗагрузкаДанных.Форма.Форма, Справочник.Контрагенты.ФормаВыбора.

Поведение окна задаёт параметр РежимОткрытияОкнаФормы:

РежимЧто делает
Независимыйобычное окно, пользователь работает с чем угодно
БлокироватьОкноВладельцаблокирует только форму-владельца
БлокироватьВесьИнтерфейсведёт себя как модальное окно

Чтобы форма выглядела как классический диалог «поверх всего», её открывают так:

ОткрытьФорму("ОбщаяФорма.ВводПараметров", , ЭтотОбъект, ,
    , , , РежимОткрытияОкнаФормы.БлокироватьВесьИнтерфейс);

Третий параметр — владелец окна (ЭтотОбъект текущей формы). Он нужен, чтобы платформа связала дочернее окно с родительским и корректно вернула фокус.

Устаревший метод ОткрытьФормуМодально использовать не нужно: он остался для совместимости и несовместим с веб-клиентом без модальности. Везде применяйте ОткрытьФорму с нужным режимом окна.

Передаём параметры в форму и забираем результат

Диалог редко бывает «в одну сторону». Обычно надо передать в форму начальные данные и получить обратно то, что ввёл пользователь.

Передача параметров — вторым аргументом ОткрытьФорму. Это структура, её читают в обработчике ПриСозданииНаСервере открываемой формы.

Вызов:

ПараметрыФормы = Новый Структура;
ПараметрыФормы.Вставить("Контрагент", Объект.Контрагент);
ПараметрыФормы.Вставить("Период", ТекущаяДата());
ОткрытьФорму("ОбщаяФорма.ВводПараметров", ПараметрыФормы, ЭтотОбъект);

Приём внутри формы диалога:

&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
    Если Параметры.Свойство("Контрагент") Тогда
        ВыбранныйКонтрагент = Параметры.Контрагент;
    КонецЕсли;
КонецПроцедуры

Возврат результата — через Закрыть(ВозвращаемоеЗначение). Форма диалога при закрытии передаёт значение:

&НаКлиенте
Процедура ОК(Команда)
    Результат = Новый Структура("Контрагент, Сумма", ВыбранныйКонтрагент, Сумма);
    Закрыть(Результат);
КонецПроцедуры

Чтобы поймать это значение, вызывающий код передаёт в ОткрытьФорму описание оповещения о закрытии — процедуру, которая получит результат:

&НаКлиенте
Процедура ВыбратьПараметры(Команда)
    Оповещение = Новый ОписаниеОповещения("ПослеВыбора", ЭтотОбъект);
    ОткрытьФорму("ОбщаяФорма.ВводПараметров", , ЭтотОбъект, , , ,
        Оповещение, РежимОткрытияОкнаФормы.БлокироватьВесьИнтерфейс);
КонецПроцедуры

&НаКлиенте
Процедура ПослеВыбора(Результат, ДопПараметры) Экспорт
    Если Результат <> Неопределено Тогда
        Объект.Контрагент = Результат.Контрагент;
    КонецЕсли;
КонецПроцедуры

Проверяйте результат на Неопределено: если пользователь закрыл окно крестиком, вернётся именно оно, а не ваша структура. Без проверки получите ошибку обращения к полю.

Два практических правила по данным диалога:

  • 🔑 Передавайте в форму примитивы и ссылки, а не громоздкие объекты. Параметры сериализуются и идут на сервер открываемой формы — тяжёлые таблицы лучше собрать уже внутри формы запросом.
  • 🧷 Если результат нужен не сразу, а внутри обработчика оповещения, передайте вспомогательные данные третьим аргументом ОписаниеОповещения — они придут в ДопПараметры обработчика. Так не приходится хранить промежуточные значения в реквизитах формы.

Управляем элементами формы на лету

Диалог редко статичен: одни поля должны прятаться, другие — становиться недоступными в зависимости от выбора. Это делают через коллекцию Элементы — на клиенте.

Основные свойства, которые меняют поведение:

  • 👁 Видимость — скрыть или показать поле;
  • 🔒 Доступность — сделать поле «серым», только для чтения;
  • ✳️ ТолькоПросмотр — у таблиц и формы в целом;
  • 🏷 Заголовок — сменить подпись элемента.
&НаКлиенте
Процедура ВидОперацииПриИзменении(Элемент)
    ЭтоВозврат = (ВидОперации = "Возврат");
    Элементы.Основание.Видимость = ЭтоВозврат;
    Элементы.Сумма.Доступность = Не ЭтоВозврат;
КонецПроцедуры

Если логика показа повторяется (при открытии и при изменении реквизита), её выносят в одну процедуру и зовут из обоих обработчиков — чтобы правило лежало в одном месте.

Для оформления по условию (цвет строки, шрифт) надёжнее не менять свойства из кода, а настроить условное оформление формы или динамического списка: платформа применит его сама при перерисовке.

Не пересоздавайте элементы программно без необходимости. Добавление колонок и полей через Элементы.Добавить тяжелее, чем переключение видимости заранее заготовленных. Программное создание оправдано, когда состав полей заранее неизвестен.

Диалоги во внешних обработках

Внешняя обработка — это файл .epf, который открывают без изменения конфигурации. У неё есть собственная форма, и она тоже работает как диалог.

Два способа запустить:

  1. Интерактивно. Пользователь открывает обработку через Файл → Открыть или раздел НСИ и администрирование → Печатные формы, отчёты и обработки (в БП 3.0 — подсистема дополнительных обработок). Форма обработки показывается как обычное окно.

  2. Из кода. Подключают обработку и открывают её форму программно:

&НаСервере
Функция ПолучитьИмяФормыОбработки()
    Адрес = ПоместитьВоВременноеХранилище(
        Новый ДвоичныеДанные("C:\Обработки\Диалог.epf"));
    ИмяОбработки = ВнешниеОбработки.Подключить(Адрес, , Ложь);
    Возврат "ВнешняяОбработка." + ИмяОбработки + ".Форма";
КонецФункции

Дальше имя передают в ОткрытьФорму — с теми же параметрами и оповещением о закрытии, что и для встроенной формы.

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

Для регулярных задач обработку регистрируют как дополнительную (справочник «Дополнительные отчёты и обработки») — тогда она доступна из интерфейса и не требует ручного открытия файла каждый раз.

Асинхронность: почему модальные вызовы заменяют оповещениями

В типовых конфигурациях свойство конфигурации «Режим использования модальности» обычно стоит Не использовать. Это требование веб-клиента: браузер не умеет останавливать выполнение кода на модальном окне. При таком режиме Вопрос, Предупреждение и ОткрытьФормуМодально вызовут ошибку.

Вместо них — асинхронные пары с описанием оповещения:

Модальный методАсинхронная замена
ВопросПоказатьВопрос
ПредупреждениеПоказатьПредупреждение
ВвестиЧислоПоказатьВводЧисла
ВвестиСтрокуПоказатьВводСтроки
ВвестиДатуПоказатьВводДаты

Логика та же, что при закрытии формы: результат приходит не в переменную, а в процедуру-обработчик.

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

&НаКлиенте
Процедура ПослеВопроса(Результат, ДопПараметры) Экспорт
    Если Результат = КодВозвратаДиалога.Да Тогда
        ПровестиНаСервере();
    КонецЕсли;
КонецПроцедуры

С платформы 8.3.18 доступен более читаемый синтаксис — асинхронные функции и оператор Ждать:

&НаКлиенте
Асинх Процедура Провести(Команда)
    Ответ = Ждать ВопросАсинх("Провести документ?", РежимДиалогаВопрос.ДаНет);
    Если Ответ = КодВозвратаДиалога.Да Тогда
        ПровестиНаСервере();
    КонецЕсли;
КонецПроцедуры

Код выглядит линейно, как со старым Вопрос, но под капотом остаётся неблокирующим. Для нового кода это предпочтительный вариант, если ваша платформа не ниже 8.3.18.

Разница особенно заметна, когда диалогов несколько подряд. На оповещениях каждый следующий вопрос задают из обработчика предыдущего — получается цепочка процедур, которую тяжело читать. С Ждать та же логика ложится в один метод:

&НаКлиенте
Асинх Процедура Оформить(Команда)
    Если Ждать ВопросАсинх("Сохранить черновик?", РежимДиалогаВопрос.ДаНет)
        = КодВозвратаДиалога.Да Тогда
        Сумма = Ждать ВвестиЧислоАсинх(0, "Сумма", 15, 2);
        Если Сумма <> Неопределено Тогда
            ЗаписатьНаСервере(Сумма);
        КонецЕсли;
    КонецЕсли;
КонецПроцедуры

Когда перейти на Ждать нельзя (старая платформа), именованные обработчики с понятными именами и передачей контекста через ДопПараметры остаются рабочим решением — просто их больше.

Частые ошибки при работе с диалогами

Разбор по симптому — от самого частого к редкому.

Диагностика: выберите симптом

Производительность и привычки, экономящие серверные вызовы

Диалог на управляемой форме — это клиент-серверное взаимодействие. Каждый переход &НаКлиенте → &НаСервере стоит сетевого обращения.

  • 📦 Собирайте данные пачкой. Не дёргайте сервер в цикле по строкам таблицы — передайте всю таблицу одним вызовом и обработайте на сервере.
  • ⚡ Используйте &НаСервереБезКонтекста для процедур, которым не нужны данные формы: платформа не гоняет контекст формы туда-обратно, вызов легче.
  • 🎛 Готовьте варианты видимости заранее. Переключать Видимость у готовых элементов дешевле, чем создавать их через Элементы.Добавить при каждом открытии.
  • 🔁 Не открывайте форму в цикле. Если нужно обработать список, покажите один диалог с таблицей, а не по окну на каждую позицию.

Для интеграции с внешним сервисом (HTTP-запрос по результату диалога) выполняйте сам запрос на сервере в &НаСервереБезКонтекста, а на клиенте оставляйте только показ окна и обработку ответа. Длинный сетевой вызов не должен висеть на клиентской процедуре.

Частые вопросы

Чем `Сообщить()` отличается от `Предупреждение()`?
Предупреждение — модальное окно с кнопкой ОК, останавливает выполнение. Сообщить (точнее, объект СообщениеПользователю) выводит текст в нижнюю панель, не прерывая работу, и может подсветить конкретное поле формы.
Как сделать диалог с несколькими полями ввода?
Системные ВвестиЧисло/ВвестиСтроку вводят одно значение. Для нескольких полей создайте управляемую форму с нужными реквизитами и откройте её через ОткрытьФорму, вернув результат структурой в оповещении о закрытии.
Почему не срабатывает `Вопрос` в веб-клиенте?
В конфигурации выключена модальность. Браузер не может остановить код на модальном окне, поэтому нужны асинхронные ПоказатьВопрос/ВопросАсинх с обработчиком результата.
Можно ли открыть одну форму диалога несколько раз?
Да. Параметр уникальности окна (Уникальность в ОткрытьФорму) задаёт ключ: при разных ключах открываются отдельные окна, при одинаковом повторный вызов активирует уже открытое.
Как вернуть из формы несколько значений сразу?
Соберите их в структуру или список значений и передайте в Закрыть(Результат). Вызывающий код получит объект целиком в процедуре оповещения о закрытии.