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