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