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