Как заполнить таблицу на форме документа из внешней обработки без блокировки объекта

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

Работа с обычными формами в 1С:Предприятии 8 часто преподносит сюрпризы, особенно когда речь идет о взаимодействии между различными объектами — например, формой документа и внешней обработкой. Одной из наиболее распространенных задач является заполнение данных на форме документа с помощью вспомогательной обработки. Однако на этом пути программисты часто сталкиваются с ошибкой «Объект заблокирован» или проблемой, когда данные в таблицу попадают, но не отображаются на экране. В этой статье мы подробно разберем, как правильно организовать этот процесс, избежав конфликтов блокировок и обеспечив корректное обновление интерфейса.

Проанализируем причину возникновения ошибки блокировки

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

Важно понимать: если ваша задача — заполнить табличное поле, которое не связано с метаданными документа (то есть это произвольная таблица значений на форме), вам вообще не нужно обращаться к объекту документа в базе данных. Нужно работать напрямую с контекстом формы.

Способ 1: Использование механизма «Владелец формы»

Это самый простой и прямой метод передачи данных в обычных формах. Рассмотрим по шагам, как его реализовать. Сначала в форме документа нам нужно правильно вызвать внешнюю обработку, назначив форму документа «владельцем» формы обработки.

В модуле формы документа напишем следующий код:


Процедура КнопкаЗаполнитьНажатие(Кнопка)
    // Получаем внешнюю обработку
    ПутьКФайлу = "C:\MyReports\FillTable.epf";
    Обработка = ВнешниеОбработки.Создать(ПутьКФайлу);
    
    // Получаем форму обработки и явно указываем владельца (ЭтаФорма)
    ФормаОбработки = Обработка.ПолучитьФорму("Форма", ЭтаФорма);
    ФормаОбработки.Открыть();
КонецПроцедуры

Теперь проанализируем, что происходит внутри внешней обработки. Поскольку мы указали ЭтаФорма как владельца, мы можем в любой момент обратиться к элементам формы документа через свойство ВладелецФормы.

В модуле формы внешней обработки:


Процедура КомандаВыполнитьЗаполнение()
    // Проверяем, что владелец — это действительно форма
    Если ТипЗнч(ЭтаФорма.ВладелецФормы) = Тип("Форма") Тогда
        
        // Допустим, мы сформировали таблицу значений ЛокальнаяТЗ
        ЛокальнаяТЗ = СформироватьНужныеДанные();
        
        // Обращаемся напрямую к элементу на форме документа
        // Предположим, табличное поле на форме документа называется "ТЗ_Данные"
        ЭлементДокумента = ЭтаФорма.ВладелецФормы.ЭлементыФормы.ТЗ_Данные;
        
        // Присваиваем значение
        ЭлементДокумента.Значение = ЛокальнаяТЗ;
        
        // Чтобы колонки отрисовались (если они не заданы жестко), вызываем СоздатьКолонки
        ЭлементДокумента.СоздатьКолонки();
        
        // Закрываем обработку после завершения
        ЭтаФорма.Закрыть();
    КонецЕсли;
КонецПроцедуры

Способ 2: Использование оповещений (самый надежный метод)

Если мы хотим сделать архитектуру нашего решения более гибкой и избежать жестких связей между объектами, выясним, как работает механизм оповещений. Этот метод позволяет форме документа «слушать» события, которые происходят в системе, и реагировать на них.

Шаг 1. В форме документа создадим предопределенную процедуру ОбработкаОповещения. Она будет принимать данные от внешней обработки.


Процедура ОбработкаОповещения(ИмяСобытия, Параметр, Источник)
    Если ИмяСобытия = "ЗаполнениеЗавершено" Тогда
        // В переменной Параметр пришла наша ТаблицаЗначений
        ЭлементыФормы.ТЗ_Данные.Значение = Параметр;
        ЭлементыФормы.ТЗ_Данные.СоздатьКолонки();
        
        // Принудительно обновляем форму, чтобы данные прорисовались
        ЭтаФорма.Обновить();
    КонецЕсли;
КонецПроцедуры

Шаг 2. Во внешней обработке, когда данные готовы, мы просто «кричим» системе о том, что всё готово, используя метод Оповестить.


Процедура КнопкаОкНажатие(Кнопка)
    ТЗ = СформироватьРезультат();
    // Посылаем сигнал всем открытым формам
    Оповестить("ЗаполнениеЗавершено", ТЗ, ЭтаФорма);
    ЭтаФорма.Закрыть();
КонецПроцедуры

Этот способ хорош тем, что он полностью исключает ошибки блокировки, так как код присвоения данных выполняется в контексте самой формы документа, которая и так владеет объектом.

Выясним причину проблем с обновлением интерфейса

Иногда программисты жалуются: «Я передал данные, отладчик показывает, что в таблице 10 строк, но на экране пусто». Посмотрим на типичные ошибки:

  1. Отсутствие связи с данными. Убедитесь, что у табличного поля (элемента управления) в свойстве Данные указано имя переменной модуля формы или реквизита. Если поле пустое, оно живет «само по себе», и обращаться к нему нужно через ЭлементыФормы.ИмяПоля.Значение.
  2. Проблема метода СоздатьКолонки. Если вы в конфигураторе вручную настроили красивые заголовки, ширину и шрифты колонок, вызов СоздатьКолонки() все это удалит и создаст стандартные колонки по типам из Таблицы Значений. В этом случае вместо присвоения всей таблицы лучше использовать Загрузить().
  3. Использование метода Обновить(). В обычных формах графическая оболочка иногда «засыпает». Вызов ЭтаФорма.Обновить() заставляет платформу перерисовать все элементы управления.

Разберем пример обновления без разрушения структуры колонок:


// Вместо замены всей таблицы, просто обновляем строки
ЭлементыФормы.ТЗ_Данные.Значение.Очистить();
Для Каждого СтрокаИзИсточника Из СформированнаяТЗ Цикл
    НоваяСтрока = ЭлементыФормы.ТЗ_Данные.Значение.Добавить();
    ЗаполнитьЗначенияСвойств(НоваяСтрока, СтрокаИзИсточника);
КонецЦикла;

Рекомендации по работе с данными

Если ваша внешняя обработка должна заполнять не просто временную таблицу, а именно Табличную Часть документа, то лучшим решением будет передача ссылки на сам ДокументОбъект. В обычных формах ДокументОбъект доступен напрямую из модуля формы.

Рассмотрим, как передать объект документа в обработку:


// В форме документа
ФормаОбработки = Обработка.ПолучитьФорму("Форма");
// Передаем весь объект документа в реквизит обработки
ФормаОбработки.ДокументДляЗаполнения = ЭтаФорма.ДокументОбъект;
ФормаОбработки.ОткрытьМодально();
// После закрытия обработки данные в объекте уже изменены

В этом случае внутри обработки вы работаете с ДокументДляЗаполнения, и поскольку это ссылка на тот же участок памяти, что и в открытой форме, изменения появятся в форме мгновенно. При этом нельзя вызывать ДокументДляЗаполнения.Записать() внутри обработки, иначе вы получите ту самую ошибку блокировки. Запись должен инициировать пользователь, нажав кнопку «ОК» в самой форме документа.

Подводя итог, можно сказать, что ключ к успеху в работе с внешними обработками в 1С 8.3 (Обычные формы) — это правильное управление контекстом. Либо мы работаем через ВладелецФормы, либо через Оповещение, либо передаем ссылку на ДокументОбъект, никогда не пытаясь получить его заново из базы данных через ПолучитьОбъект(), пока форма открыта.

← На главную