Как перенести редактирование данных регистра сведений из формы документа 8.2 в управляемую форму 8.3

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

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

В чем заключается проблема при переносе?

В обычных формах (8.2) мы могли добавить на форму реквизит с типом РегистрСведенийНаборЗаписей, вынести его в виде табличного поля и напрямую управлять им. Код вроде ТаблицаРегистра.Отбор.Документ.Установить(Ссылка); ТаблицаРегистра.Прочитать(); работал прямо в модуле формы. В управляемых формах (8.3) ситуация принципиально иная: данные отделены от представления.

Проанализируем основные причины, почему старый код выдает ошибки:

  1. Разделение на Клиент и Сервер: Объект типа РегистрСведенийНаборЗаписей не существует на клиенте. На форме он превращается в тип ДанныеФормыКоллекция, у которого нет методов Прочитать() или Записать().
  2. Отсутствие контекста: На клиенте нет прямой связи с базой данных. Чтобы получить записи из регистра, необходимо явно обратиться к серверу.
  3. Типизация: В управляемой форме реквизиты формы — это лишь структуры данных для отображения, а не сами объекты метаданных.

Разберем по шагам наиболее надежный и гибкий способ реализации этой задачи — использование промежуточной Таблицы Значений на форме с программной синхронизацией с регистром на сервере.

Шаг 1. Создание реквизитов управляемой формы

Для начала нам необходимо подготовить структуру данных в редакторе формы документа. Вместо попыток использовать набор записей как основной тип, мы создадим таблицу, которая будет хранить данные в памяти формы.

  1. Перейдем на закладку "Реквизиты" формы документа.
  2. Добавим новый реквизит (например, с именем ТаблицаРегистра) и установим ему тип ТаблицаЗначений.
  3. Внутри этой таблицы добавим колонки, соответствующие измерениям и ресурсам вашего регистра сведений (например, Продукция, Номенклатура, Количество, ДокументОснование).
  4. Перетащим этот реквизит в элементы формы, чтобы создать таблицу. Не забудьте разрешить редактирование в свойствах таблицы.

Шаг 2. Реализация чтения данных при выборе строки

Теперь выясним, как наполнять эту таблицу данными. Предположим, у нас есть основная табличная часть документа "Производство", и при активации строки в ней мы хотим видеть связанные записи в нашей нижней таблице. Используем для этого событие ПриАктивизацииСтроки основной таблицы.

Важный нюанс: Чтобы избежать "подвисаний" интерфейса из-за постоянных серверных вызовов при перемещении по строкам, рекомендуется использовать обработчик ожидания. Но для начала разберем базовую логику.


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

&НаСервере
Процедура ОбновитьДанныеРегистраНаСервере(Знач ВыбраннаяНоменклатура)
    // Очищаем текущую таблицу на форме
    ТаблицаРегистра.Очистить();
    
    // Запросом получаем данные из регистра сведений
    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ
        |   Регистр.Продукция КАК Продукция,
        |   Регистр.Количество КАК Количество
        |ИЗ
        |   РегистрСведений.ВашРегистр КАК Регистр
        |ГДЕ
        |   Регистр.ДокументОснование = &ДокументОснование
        |   И Регистр.Продукция = &ВыбраннаяНоменклатура";
    
    Запрос.УстановитьПараметр("ДокументОснование", Объект.Ссылка);
    Запрос.УстановитьПараметр("ВыбраннаяНоменклатура", ВыбраннаяНоменклатура);
    
    РезультатЗапроса = Запрос.Выполнить();
    Если НЕ РезультатЗапроса.Пустой() Тогда
        // Заполняем реквизит формы типа ТаблицаЗначений
        Выборка = РезультатЗапроса.Выбрать();
        Пока Выборка.Следующий() Цикл
            НоваяСтрока = ТаблицаРегистра.Добавить();
            ЗаполнитьЗначенияСвойств(НоваяСтрока, Выборка);
        КонецЦикла;
    КонецЕсли;
КонецПроцедуры

Шаг 3. Сохранение изменений в регистр

Поскольку наша таблица на форме — это просто ТаблицаЗначений, изменения в ней не попадают в базу автоматически. Нам нужно прописать логику записи. Лучше всего это делать в обработчике ПередЗаписьюНаСервере самого документа.

Рассмотрим алгоритм записи данных:


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

Альтернативный способ: Использование типа РегистрСведенийНаборЗаписей в реквизитах формы

Существует возможность оставить тип реквизита формы РегистрСведенийНаборЗаписей.[Имя], что чуть ближе к логике 8.2, но работа с ним всё равно потребует серверных преобразований. Посмотрим на пример кода, который заменяет Прочитать():


&НаСервере
Процедура ЗагрузитьНаборЗаписейНаСервере()
    // Создаем объект набора записей в памяти сервера
    НаборОбъект = РегистрыСведений.ВашРегистр.СоздатьНаборЗаписей();
    НаборОбъект.Отбор.Документ.Установить(Объект.Ссылка);
    НаборОбъект.Прочитать();
    
    // Преобразуем объект сервера в реквизит формы (коллекцию)
    ЗначениеВРеквизитФормы(НаборОбъект, "ТаблицаРегистра");
КонецПроцедуры

Для сохранения используется обратная функция РеквизитФормыВЗначение. Этот метод удобен тем, что 1С сама контролирует структуру колонок, но он менее гибкий, если вам нужно отображать в таблице данные из разных источников или вычисляемые поля.

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

Проанализируем ситуацию: если пользователь быстро пролистывает список товаров в верхней таблице, сервер будет засыпаться запросами на обновление нижней таблицы. Чтобы этого избежать, разберем внедрение задержки.


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

&НаКлиенте
Процедура ИсполнитьОбновлениеДанных()
    // Этот код выполнится только когда пользователь остановится на строке
    ТекущиеДанные = Элементы.ТабличнаяЧастьПроизводство.ТекущиеДанные;
    Если ТекущиеДанные <> Неопределено Тогда
        ОбновитьДанныеРегистраНаСервере(ТекущиеДанные.Номенклатура);
    КонецЕсли;
КонецПроцедуры

Подведем итоги

Перенос функционала из 8.2 в 8.3 — это не просто копирование кода, а переосмысление архитектуры. Главное правило: забудьте о прямом управлении объектами метаданных на клиенте. Используйте Таблицу Значений на форме для удобства пользователя и методы ЗначениеВРеквизитФормы / РеквизитФормыВЗначение или прямые запросы для синхронизации с базой данных на сервере.

Такой подход делает форму быстрой, отказоустойчивой и полностью совместимой с тонким клиентом и веб-клиентом 1С.

← На главную