При работе с внешним компонентом FormEx в платформе 1С:Предприятие 7.7 часто возникает необходимость выполнить действия с документом после закрытия его формы — например, заполнить новый общий реквизит или передать данные во внешнюю систему. Однако попытка получить объект документа и вызвать метод Записать() непосредственно внутри событии ПослеЗакрытия(Конт) приводит к ошибке «Док заблокирован».
В этой статье мы разберем причину возникновения данной ошибки, а также рассмотрим проверенные способы её обхода с использованием возможностей платформы и библиотеки 1С++.
Проанализируем механику работы платформы 1С 7.7 и компонента FormEx. Событие ПослеЗакрытия(Конт) выбывается сразу после закрытия диалогового окна формы. Однако сама платформа снятие блокировки с объекта (документа) производит лишь после полного завершения цепочки вызовов закрытия окна и возврата управления в главный цикл обработки событий.
Когда мы пытаемся создать объект Документ, найти его по ссылке из контекста Конт.ТекущийДокумент() и выполнить модификацию с вызовом Записать(), платформа отвергает действие, так как форма еще удерживает фоновую блокировку записи.
Наиболее простое и элегантное решение — разнести момент закрытия формы и момент записи документа по времени. Для этого используется штатная процедура 1С 7.7 ОбработкаОжидания().
Рассмотрим по шагам, как реализовать этот подход:
ПослеЗакрытия(Конт) проверяем, что закрытый контекст является документом и он сохранен в базе.ОбработкаОжидания.Посмотрим на пример реализации в глобальном модуле:
Переменная глДокументДляЗаписи;
Процедура ПослеЗакрытия(Конт)
Если ТипЗначенияСтр(Конт) = "ГруппаКонтекста" Тогда
Если Конт.Вид() = "Документ" Тогда
Если Конт.ТекущийДокумент().Выбран() = 1 Тогда
глДокументДляЗаписи = Конт.ТекущийДокумент();
ОбработкаОжидания("глОтложеннаяЗаписьДокумента", 1);
КонецЕсли;
КонецЕсли;
КонецЕсли;
КонецПроцедуры
Процедура глОтложеннаяЗаписьДокумента()
ОбработкаОжидания("глОтложеннаяЗаписьДокумента", 0); // Отключаем таймер
Если ПустоеЗначение(глДокументДляЗаписи) = 0 Тогда
Док = СоздатьОбъект("Документ." + глДокументДляЗаписи.Вид());
Если Док.НайтиДокумент(глДокументДляЗаписи) = 1 Тогда
Док.НашОбщийРеквизит = "Значение";
Док.Записать();
КонецЕсли;
глДокументДляЗаписи = "";
КонецЕсли;
КонецПроцедуры
К моменту вызова процедуры глОтложеннаяЗаписьДокумента() главный цикл обработки событий 1С успевает завершить закрытие окна, и блокировка с документа полностью снимается.
Если задача заключается в гарантии записи реквизита при любом сохранении документа (а не только при закрытии окна), то закрытие формы — не самое лучшее место для такой логики. Например, если пользователь закрывает форму без сохранения или нажимает «Отмена», отложенная запись может модифицировать документ вопреки логике.
В таком случае рекомендуется использовать класс Hooker (Перехватчик) из библиотеки 1С++. Он позволяет перехватывать глобальное событие СобытиеГМ_ПриЗаписи до или в момент сохранения объекта.
Разберем порядок настройки перехватчика:
Hooker через ЗагрузитьВнешнююКомпоненту("1cpp.dll").Рассмотрим пример кода инициализации перехватчика в глобальном модуле:
Переменная Перехватчик;
Процедура ПриНачалеРаботыСистемы()
ЗагрузитьВнешнююКомпоненту("1cpp.dll");
Перехватчик = СоздатьОбъект("Hooker");
Перехватчик.Заразить("СобытиеГМ_ПриЗаписи");
КонецПроцедуры
Процедура СобытиеГМ_ПриЗаписи(Конт, ФлагЗапроса)
// Данная процедура перехватывает ПриЗаписи для всех документов
Если Конт.Вид() = "Документ" Тогда
Конт.НашОбщийРеквизит = "Значение";
КонецЕсли;
КонецПроцедуры
Выясним, какие еще подходы можно применить и о каких нюансах стоит помнить:
ПриОткрытии() формы документа или в процедуру ВводНового(). При последующем нажатии кнопки «ОК» или «Записать» пользователем реквизит сохранится штатно.1SJOURN или DH...), его можно обновить прямым SQL-запросом UPDATE в процедуре ПослеЗакрытия. Прямые запросы игнорируют объектные блокировки платформы 1С.Важное предупреждение: При изменении реквизитов уже проведенных документов после их закрытия может потребоваться повторное проведение объекта, если реквизит участвует в формировании движений по регистрам.