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