Как реализовать автоматическое обновление подчиненной таблицы при переходе по строкам в управляемой форме 1С?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При разработке интерфейсов на управляемых формах 1С часто возникает классическая задача: реализовать связь «Мастер-Деталь» (Master-Detail). Например, у нас есть основная таблица со списком документов или контрагентов, и мы хотим, чтобы при выделении строки в этой таблице во второй (подчиненной) таблице автоматически отображались только связанные данные (контакты, спецификации и т.д.).

В обычных формах (1С 8.2 и ранее) это решалось довольно просто, однако переход на управляемые формы внес свои коррективы в событийную модель. В этой статье мы подробно разберем, как поймать момент перехода с одной строки на другую и как максимально эффективно обновить зависимые данные, не перегружая интерфейс и сервер.

Использование основного события ПриАктивизацииСтроки

Для решения поставленной задачи в управляемых формах основным инструментом является событие ПриАктивизацииСтроки. Рассмотрим его механику. Это событие генерируется элементом формы (таблицей) в тот момент, когда курсор перемещается на новую строку, либо когда таблица получает фокус ввода. Проанализируем, почему некоторые разработчики ошибочно полагают, что событие «не срабатывает».

Событие ПриАктивизацииСтроки срабатывает очень часто: при открытии формы, при обновлении данных, при сортировке и даже при потере фокуса. Если внутри обработчика написать неоптимизированный код, форма начнет «подтормаживать» при обычном пролистывании списка стрелками клавиатуры. Выясним причину: каждый раз, когда вы нажимаете стрелку «вниз», система пытается выполнить ваш код. Если там есть серверный вызов, происходит передача контекста формы на сервер и обратно, что в веб-клиенте или при слабом интернете превращается в серьезную проблему.

Рассмотрим пример правильной реализации фильтрации второй таблицы на клиенте, если данные в ней уже загружены:


&НаКлиенте
Процедура СписокМастерПриАктивизацииСтроки(Элемент)
    
    // Получаем текущие данные выделенной строки
    ТекущиеДанные = Элемент.ТекущиеДанные;
    
    // Обязательно проверяем на Неопределено, так как при очистке списка 
    // или открытии пустой формы данных может не быть
    Если ТекущиеДанные = Неопределено Тогда
        // Сбрасываем фильтр подчиненной таблицы
        Элементы.СписокДетали.ОтборСтрок = Новый ФиксированнаяСтруктура("КлючСвязи", Неопределено);
    Иначе
        // Устанавливаем фильтр по ключевому полю
        // Используем свойство ОтборСтрок элемента формы
        СтруктураОтбора = Новый ФиксированнаяСтруктура("КлючСвязи", ТекущиеДанные.КлючСвязи);
        Элементы.СписокДетали.ОтборСтрок = СтруктураОтбора;
    КонецЕсли;
    
КонецПроцедуры

Особенности работы со свойством ОтборСтрок

Разберем важный технический нюанс. Свойство ОтборСтрок доступно только для элементов формы типа «Таблица», связанных с прикладными объектами (например, ТаблицаЗначений или ДанныеФормыКоллекция). Важно помнить: этот отбор работает исключительно визуально и на стороне клиента. Данные в самой коллекции (в памяти) остаются неизменными, платформа просто скрывает строки, не подходящие под критерий.

Если во второй таблице находятся десятки тысяч строк, использование ОтборСтрок может быть неэффективным, так как клиентскому приложению приходится пересчитывать видимость каждой строки. В таких ситуациях лучше использовать серверную фильтрацию и перезаполнение коллекции, но делать это нужно крайне осторожно.

Оптимизация производительности: Обработчик ожидания

Проанализируем ситуацию, когда нам необходимо при смене строки не просто отфильтровать уже имеющиеся данные, а сходить на сервер (например, выполнить тяжелый запрос к базе данных). Если делать это напрямую в ПриАктивизацииСтроки, пользователь не сможет быстро листать список. Решение заключается в использовании метода ПодключитьОбработчикОжидания.

Идея проста: при активации строки мы не бежим на сервер сразу, а «взводим таймер» на 0.2–0.5 секунды. Если в течение этого времени пользователь перешел на следующую строку, мы сбрасываем старый таймер и запускаем новый. Серверный вызов произойдет только тогда, когда пользователь остановится на строке.

Посмотрим на пример реализации такого подхода:


&НаКлиенте
Процедура СписокМастерПриАктивизацииСтроки(Элемент)
    // Отключаем предыдущий обработчик, если он был запущен
    ОтключитьОбработчикОжидания("ВыполнитьОбновлениеПодчиненнойТаблицы");
    
    // Запускаем новый обработчик с задержкой в 0.3 секунды
    ПодключитьОбработчикОжидания("ВыполнитьОбновлениеПодчиненнойТаблицы", 0.3, Истина);
КонецПроцедуры

&НаКлиенте
Процедура ВыполнитьОбновлениеПодчиненнойТаблицы()
    // Проверяем наличие текущей строки
    ТекущаяСтрока = Элементы.СписокМастер.ТекущаяСтрока;
    Если ТекущаяСтрока = Неопределено Тогда
        Возврат;
    КонецЕсли;
    
    // Выполняем обновление (может включать серверный вызов)
    ОбновитьДанныеНаСервере(ТекущаяСтрока);
КонецПроцедуры

Предотвращение лишних срабатываний (Циклов)

Часто в управляемых формах возникает проблема «зацикливания»: обновление подчиненной таблицы может вызвать перерисовку всей формы, что снова спровоцирует событие ПриАктивизацииСтроки в основной таблице. Чтобы избежать бесконечных вызовов и лишней нагрузки, рекомендуется хранить идентификатор последней обработанной строки в переменной формы.

Выясним, как это работает:

  1. Создаем переменную на форме (или скрытый реквизит) для хранения ИдентификаторПредыдущейСтроки.
  2. В событии ПриАктивизацииСтроки сравниваем текущий идентификатор с сохраненным.
  3. Если они совпадают — ничего не делаем.
  4. Если отличаются — выполняем логику обновления и сохраняем новый идентификатор.

Использование Динамических списков как альтернатива

Если ваши таблицы — это не просто временные данные во внешней обработке, а списки справочников или документов, рассмотрим профессиональный стандарт реализации Master-Detail через ДинамическийСписок. В этом случае программирование в ПриАктивизацииСтроки вообще не требуется.

В платформе 1С реализован механизм «Связь по параметрам выбора». Вы можете настроить второй динамический список так, чтобы он автоматически пересчитывал свой запрос в зависимости от текущего значения в первом списке. Это делается в свойствах элемента формы:

  1. Находим поле «Параметры выбора» у подчиненной таблицы.
  2. Указываем связь с полем основной таблицы.
  3. Платформа берет на себя всю работу по оптимизации запросов и обновлению интерфейса.

Выводы и рекомендации

Подводя итог, можно сказать, что событие ПриАктивизацииСтроки является мощным, но «опасным» инструментом. Для простых задач во внешних обработках с небольшим объемом данных идеально подходит связка ПриАктивизацииСтроки + ОтборСтрок. Для сложных систем с большими объемами данных обязательно используйте ПодключитьОбработчикОжидания и старайтесь выполнять серверные вызовы через &НаСервереБезКонтекста, чтобы минимизировать объем передаваемых данных между клиентом и сервером.

Помните, что отзывчивость интерфейса — это приоритет номер один для пользователя. Применение задержек в несколько миллисекунд визуально незаметно для человека, но колоссально снижает нагрузку на систему при активной работе со списками.

← На главную