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