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