Разберем ситуацию, которая часто ставит в тупик даже опытных разработчиков 1С при работе с управляемыми формами. Представим сценарий: на форме расположена таблица (это может быть как табличная часть объекта, так и динамический список или таблица значений), в которой одна из колонок имеет составной тип данных. Мы назначаем обработчик события ПриИзменении для этой колонки, ожидая стандартного поведения платформы, но сталкиваемся со странностью: после выбора типа данных обработчик срабатывает, а после выбора самого значения — нет.
В этой статье мы подробно проанализируем, почему так происходит, выясним роль версии платформы и, самое главное, найдем критическую ошибку в коде, которая прерывает нормальный цикл работы интерфейса.
Для начала рассмотрим, как платформа 1С версии 8.3 должна обрабатывать интерактивное изменение поля с составным типом. По стандартам управляемого интерфейса, это действие является двухэтапным:
Неопределено на пустую ссылку выбранного типа. В этот момент событие ПриИзменении должно вызваться первый раз.ПриИзменении должно вызваться второй раз.Проанализируем ситуацию: если на вашей платформе (например, 8.3.15 или 8.3.16) это событие срабатывает только один раз, это не всегда является багом платформы, хотя в истории релизов 1С подобные ошибки фиксировались. Чаще всего причина кроется в логике кода самого обработчика.
Выясним основную причину, на которую указал автор обсуждаемой темы. Проблема заключается в использовании метода ЗначениеВРеквизитФормы() внутри серверного вызова, инициированного первым срабатыванием обработчика ПриИзменении.
Разберем по шагам, что происходит в памяти системы:
ПриИзменении, который передает управление на сервер для выполнения расчетов.ЗначениеВРеквизитФормы(ОбъектДанных, "Объект"). Этот метод полностью пересоздает программные объекты на форме, синхронизируя их с данными из прикладного объекта.Посмотрим на пример кода, который приводит к ошибке:
&НаКлиенте
Процедура ТЧПриИзменении(Элемент)
// Вызов серверной процедуры для пересчета
ПересчитатьДанныеНаСервере();
КонецПроцедуры
&НаСервере
Процедура ПересчитатьДанныеНаСервере()
// Преобразование реквизита формы в прикладной объект (например, ДокументОбъект)
ДокОбъект = РеквизитФормыВЗначение("Объект");
// Какие-то расчеты...
ДокОбъект.РассчитатьИтоги();
// КРИТИЧЕСКАЯ ОШИБКА: Полное обновление данных формы
ЗначениеВРеквизитФормы(ДокОбъект, "Объект");
КонецПроцедуры
При таком подходе платформа считает, что структура данных была обновлена извне, и прекращает дальнейшую обработку интерактивной цепочки выбора для конкретного поля.
Чтобы избежать прерывания событий, мы должны использовать локальное обновление данных. Вместо того чтобы перекачивать весь объект целиком с сервера на клиент и обратно, следует работать только с теми данными, которые непосредственно изменились.
Рассмотрим правильный подход к реализации пересчета строки таблицы. Проанализируем ситуацию: нам нужно обновить только текущую строку, не затрагивая состояние всей формы и других строк.
&НаКлиенте
Процедура ТЧПоле1ПриИзменении(Элемент)
// Получаем данные текущей строки напрямую
ТекущаяСтрока = Элементы.ТЧ.ТекущиеДанные;
// Если значение еще не заполнено (выбран только тип),
// мы можем пропустить тяжелые расчеты, но не должны ломать форму
Если ТекущаяСтрока.Поле1 = Неопределено Тогда
Возврат;
КонецЕсли;
// Выполняем расчеты без полной перезагрузки объекта
РассчитатьСпецификуНаСервере(ТекущаяСтрока.НомерСтроки);
КонецПроцедуры
&НаСервере
Процедура РассчитатьСпецификуНаСервере(НомерСтроки)
// Работаем напрямую с реквизитом формы (ДанныеФормыКоллекция)
СтрокаТЧ = Объект.ТЧ.НайтиПоИдентификатору(НомерСтроки - 1);
// Или используем другие способы позиционирования
Если СтрокаТЧ <> Неопределено Тогда
// Обновляем только нужные поля
СтрокаТЧ.Сумма = СтрокаТЧ.Количество * СтрокаТЧ.Цена;
КонецЕсли;
// Метод ЗначениеВРеквизитФормы() ЗДЕСЬ НЕ НУЖЕН!
КонецПроцедуры
Проанализируем дополнительные аспекты, которые помогут сделать работу с таблицами более стабильной:
Пустая()), возможно, стоит отложить выполнение основной логики до второго вызова события.Таким образом, мы выяснили, что странное поведение обработчика ПриИзменении — это чаще всего следствие нарушения контекста выполнения управляемой формы. Избегайте деструктивных методов обновления данных (таких как полная перезагрузка объекта через ЗначениеВРеквизитФормы) в момент интерактивного взаимодействия пользователя с элементами таблицы, и ваши формы будут работать предсказуемо и быстро.