При разработке интерфейсов на платформе 1С:Предприятие 8.3 в режиме управляемых форм часто возникает задача интерактивного взаимодействия с пользователем. Типичный сценарий: перед тем как создать новую строку в табличной части или таблице формы, необходимо уточнить параметры или получить подтверждение действия через диалоговое окно.
В немодальном режиме и при использовании асинхронных вызовов стандартный синхронный подход не работает привычным образом. Разберем по шагам, почему возникает эта проблема, как устроена работа событий таблицы формы и какие практические способы реализации существуют.
Рассмотрим механику события ПередНачаломДобавления. Данный обработчик вызывается платформой синхронно. Если мы открываем немодальное окно с помощью функции ПоказатьВопрос или асинхронных конструкций ВопросАсинх, платформа не ждет закрытия диалогового окна пользователем и считывает значение параметра Отказ в момент первой асинхронной паузы.
Поэтому идея сначала задать немодальный вопрос, дождаться ответа и только потом выставить Отказ = Истина не сработает — строка будет добавлена до того, как пользователь нажмет кнопку в диалоге.
Также проанализируем вариант «дать строке добавиться, а при отрицательном ответе удалить её». Такой подход порождает множество скрытых проблем:
Модифицированность = Истина для формы сразу при создании строки.ПриНачалеРедактирования, автопересчет итогов и серверные вызовы).Именно поэтому единственно верным архитектурным решением является немедленная отмена стандартного добавления (Отказ = Истина) с последующей ручной вставкой строки при положительном ответе.
Рассмотрим подробнее реализацию через событие ПередНачаломДобавления. Если в обработчике ответа пользователя мы снова вызовем интерактивное добавление методом Элементы.ИмяТаблицы.ДобавитьСтроку(), платформа повторно вызовет событие ПередНачаломДобавления. Чтобы избежать бесконечной рекурсии, применим переменную контекста формы в качестве управляющего флага.
Посмотрим на пример реализации в модуле формы:
&НаКлиенте
Перем РазрешеноДобавлениеБезВопроса;
&НаКлиенте
Процедура ТоварыПередНачаломДобавления(Элемент, Отказ, Копирование, Родитель, ЭтоГруппа, Иерархия)
Если РазрешеноДобавлениеБезВопроса = Истина Тогда
РазрешеноДобавлениеБезВопроса = Ложь;
Возврат;
КонецЕсли;
Отказ = Истина;
Оповещение = Новый ОписаниеОповещения("ПослеОтветаНаВопросОДобавлении", ЭтотОбъект);
ПоказатьВопрос(Оповещение, "Вы действительно хотите добавить новую позицию?", РежимДиалогаВопрос.ДаНет);
КонецПроцедуры
&НаКлиенте
Процедура ПослеОтветаНаВопросОДобавлении(Результат, ДополнительныеПараметры) Экспорт
Если Результат = КодВозвратаДиалога.Да Тогда
РазрешеноДобавлениеБезВопроса = Истина;
Элементы.Товары.ДобавитьСтроку();
КонецЕсли;
КонецПроцедуры
Разберем логику работы данного кода:
ПередНачаломДобавления.РазрешеноДобавлениеБезВопроса равен Ложь (или Неопределено), поэтому выставляется Отказ = Истина, стандартное создание строки прерывается, и открывается немодальное окно вопроса.РазрешеноДобавлениеБезВопроса = Истина и вызывается Элементы.Товары.ДобавитьСтроку().Ложь и дает строке штатно создаться с активацией фокуса на первой ячейке.Выясним причину, почему разработчики иногда предпочитают добавлять строку не методом элемента формы ДобавитьСтроку(), а напрямую в данные объекта. Это удобно, если при создании требуется сразу заполнить реквизиты строки по умолчанию на клиенте или сервере.
При программном добавлении в коллекцию Объект.Товары.Добавить() строка не переходит в режим редактирования автоматически. Чтобы передать на неё фокус и открыть ввод данных, используем свойства ТекущаяСтрока и метод ИзменитьСтроку().
Посмотрим на пример кода:
&НаКлиенте
Процедура ТоварыПередНачаломДобавления(Элемент, Отказ, Копирование, Родитель, ЭтоГруппа, Иерархия)
Отказ = Истина;
Оповещение = Новый ОписаниеОповещения("ПослеПодтвержденияВставки", ЭтотОбъект);
ПоказатьВопрос(Оповещение, "Добавить новую строку в табличную часть?", РежимДиалогаВопрос.ДаНет);
КонецПроцедуры
&НаКлиенте
Процедура ПослеПодтвержденияВставки(Результат, ДополнительныеПараметры) Экспорт
Если Результат <> КодВозвратаДиалога.Да Тогда
Возврат;
КонецЕсли;
НоваяСтрока = Объект.Товары.Добавить();
// Передаем фокус на созданную строку и переводим в режим ввода
Элементы.Товары.ТекущаяСтрока = НоваяСтрока.ПолучитьИдентификатор();
Элементы.Товары.ИзменитьСтроку();
КонецПроцедуры
Важный нюанс: при программном добавлении строки в Объект.Товары событие ПередНачаломДобавления повторно не вызывается, поэтому использование переменной-флага в данном сценарии не требуется.
Еще один практический подход заключается в замене стандартного действия командной панели таблицы:
ДобавитьТоварСВопросом) и вынесите её в командную панель.Элементы.Товары.ДобавитьСтроку().Обратите внимание: если таблица формы позволяет добавлять строки горячей клавишей Insert или через контекстное меню, переопределения только кнопки на панели недостаточно — потребуется либо полностью отключить добавление в свойствах таблицы, либо комбинировать данный способ с перехватом события ПередНачаломДобавления.