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