При разработке интерфейсов в среде «1С:Предприятие 8» программисты часто сталкиваются с классическим паттерном «Мастер-Деталь» (Master-Detail). Типичный пример: на форме расположены две связанные табличные части. В первой отображается список документов, а во второй — состав товаров выбранного в данный момент документа. При этом стандартное поведение платформы при интерактивном переходе по строкам может вызывать две неприятные проблемы:
В этой статье мы подробно разберем, как элегантно решить обе проблемы с использованием стандартов разработки «1С» и лучших практик оптимизации производительности интерфейса.
---
Выясним причину зависания интерфейса. Когда пользователь зажимает стрелку «Вниз» для быстрого поиска нужного документа в первой таблице, событие ПриАктивизацииСтроки срабатывает для каждого промежуточного документа. Если в этом событии напрямую вызывать обновление второй таблицы, платформа начнет выполнять серверные вызовы десятки раз в секунду. Это перегружает базу данных и блокирует интерфейс клиента.
Чтобы избежать этой проблемы, применим паттерн дебаунсинг (debouncing) — установим небольшую задержку (таймаут) перед обновлением. Если пользователь переходит на следующую строку быстрее, чем за 0.3 секунды, мы сбрасываем предыдущий таймер и запускаем новый. Подчиненная таблица обновится только тогда, когда пользователь остановится на конкретной строке.
Разберем по шагам реализацию данного механизма на клиенте:
Шаг 1. Обработка события активации строки
В модуле формы для первой (основной) таблицы создадим обработчик события ПриАктивизацииСтроки. В нем мы будем отключать ранее зарегистрированный обработчик ожидания и сразу подключать его заново.
&НаКлиенте
Процедура СписокДокументовПриАктивизацииСтроки(Элемент)
// Сбрасываем таймер, если пользователь продолжает перемещаться по строкам
ОтключитьОбработчикОжидания("Подключаемый_ОбновитьТаблицуТоваров");
// Запускаем таймер заново с задержкой 0.3 секунды.
// Обратите внимание: для субсекундных интервалов (менее 1 сек.)
// параметр "Однократно" должен быть равен Истина.
ПодключитьОбработчикОжидания("Подключаемый_ОбновитьТаблицуТоваров", 0.3, Истина);
КонецПроцедуры
Шаг 2. Реализация подключаемой процедуры
Теперь напишем саму процедуру, имя которой мы указали в обработчике ожидания. Она должна работать на клиенте без параметров.
&НаКлиенте
Процедура Подключаемый_ОбновитьТаблицуТоваров()
ТекущиеДанные = Элементы.СписокДокументов.ТекущиеДанные;
// Проверяем, выбрана ли строка (например, таблица могла быть очищена)
Если ТекущиеДанные = Неопределено Тогда
Объект.Товары.Очистить();
Возврат;
КонецЕсли;
// Вызываем серверную процедуру обновления данных
ОбновитьТоварыНаСервере(ТекущиеДанные.Ссылка);
КонецПроцедуры
Важное предупреждение о производительности:
Ни в коем случае не делайте контекстных вызовов сервера внутри обработчиков событий навигации без крайней необходимости! Передача всего контекста формы туда и обратно сильно бьет по производительности. Рекомендуется использовать директиву &НаСервереБезКонтекста, передавая на сервер только ссылку на документ, получать массив строк и заполнять подчиненную таблицу на клиенте. Посмотрим на пример такой оптимизации:
&НаСервереБезКонтекста
Функция ПолучитьТоварыДокумента(СсылкаНаДокумент)
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ПродажиТовары.Номенклатура,
| ПродажиТовары.Количество,
| ПродажиТовары.Цена,
| ПродажиТовары.Сумма
|ИЗ
| Документ.Продажи.Товары КАК ПродажиТовары
|ГДЕ
| ПродажиТовары.Ссылка = &Ссылка";
Запрос.УстановитьПараметр("Ссылка", СсылкаНаДокумент);
Возврат Запрос.Выполнить().Выгрузить();
КонецФункции
&НаКлиенте
Процедура ОбновитьТоварыНаСервере(СсылкаНаДокумент)
// Получаем данные без передачи контекста всей формы
ТаблицаТоваров = ПолучитьТоварыДокумента(СсылкаНаДокумент);
// Заполняем табличную часть формы на клиенте
Объект.Товары.Очистить();
Для Каждого СтрокаДанных Из ТаблицаТоваров Цикл
НоваяСтрока = Объект.Товары.Добавить();
ЗаполнитьЗначенияСвойств(НоваяСтрока, СтрокаДанных);
КонецЦикла;
КонецПроцедуры
Этот подход гарантирует моментальный отклик интерфейса даже при работе через веб-клиент или при медленном интернет-соединении.
---
По умолчанию в платформе «1С» для табличных частей включено свойство, которое автоматически создает новую строку, если пользователь нажимает клавишу «стрелка вниз» на клавиатуре, находясь на последней строчке таблицы. Это удобно при быстром ручном вводе номенклатуры, но крайне мешает в режиме просмотра или когда таблица заполняется программно.
Проанализируем доступные способы отключения автосоздания строк:
Самый простой и правильный способ решить проблему — изменить настройки элемента формы. Рассмотрим, как это сделать:
СписокДокументов или Товары).Ложь).Также это свойство можно регулировать программно, например, при создании формы на сервере:
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
Элементы.Товары.АвтоВводНовойСтроки = Ложь;
КонецПроцедуры
После этого при нажатии стрелки «Вниз» на последней строке фокус просто останется на ней же, а новая пустая строка создаваться не будет.
Если подчиненная табличная часть товаров заполняется исключительно автоматически на основе выбранного документа, пользователю вообще не должно быть разрешено добавлять новые элементы вручную.
Для полной блокировки возможности ручного добавления или удаления строк выполните программную настройку:
Элементы.Товары.ИзменятьСоставСтрок = Ложь;
При таком подходе кнопки добавления и копирования строк на панели инструментов станут недоступными, а клавиша Insert перестанет реагировать на нажатия. При этом пользователи сохранят возможность редактировать данные в уже существующих строках (например, изменять количество товара), если колонки открыты для редактирования.
Если вам требуется реализовать более сложную логику (например, запрещать добавление строк только определенным пользователям или при выполнении определенных условий), используйте интерактивный обработчик события таблицы.
Посмотрим на пример кода:
&НаКлиенте
Процедура ТоварыПередНачаломДобавления(Элемент, Отказ, Копирование, Родитель, Группа, Параметр)
// Блокируем любое интерактивное добавление новых строк
Отказ = Истина;
ПоказатьПредупреждение(, "Добавление строк вручную запрещено. Таблица заполняется автоматически!");
КонецПроцедуры
Если подчиненная таблица используется исключительно как информационная панель для визуального ознакомления с составом выбранного документа, лучшим решением будет перевести всю таблицу в режим чтения:
Элементы.Товары.ТолькоПросмотр = Истина;
Это мгновенно отключит любые интерактивные изменения: добавление, копирование, удаление строк, а также редактирование отдельных ячеек.
---
Мы детально рассмотрели лучшие практики проектирования связанных списков в «1С». Использование обработчиков ожидания (дебаунсинга) защищает вашу информационную систему от лишней нагрузки на сервер базы данных и предотвращает зависание интерфейса у конечных пользователей. В свою очередь, грамотная настройка свойств АвтоВводНовойСтроки и ИзменятьСоставСтрок делает интерфейс интуитивно понятным, предсказуемым и защищает данные от случайного искажения.