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