Как обратиться к реквизитам формы документа из внешней обработки и изменить его данные

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

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

Разберем детально, как реализовать это взаимодействие, используя современные механизмы платформы и стандарты разработки.

Метод 1. Использование механизма оповещений (рекомендуемый способ)

Наиболее правильным и архитектурно чистым способом является использование механизма ОписаниеОповещения. В этом случае форма документа «ждет» завершения работы обработки и получает результат в специальную процедуру. Рассмотрим этот процесс по шагам.

Во-первых, проанализируем вызов формы обработки из документа. Чтобы обработка знала, кто ее вызвал, и могла вернуть данные, необходимо передать владельца. В форме документа (или в модуле команды) напишем код вызова:


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

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


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

В-третьих, вернемся в форму документа и опишем процедуру завершения, указанную в ОписаниеОповещения. Именно здесь мы будем обращаться к реквизитам Объект.Товары и модифицировать их:


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

Метод 2. Обращение через ВладелецФормы напрямую

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

Проанализируем ситуацию: мы находимся в модуле формы внешней обработки и хотим очистить таблицу товаров в документе. На клиенте это будет выглядеть следующим образом:


&НаКлиенте
Процедура ОчиститьТаблицуДокумента()
    
    // Проверяем, доступен ли владелец
    Если ВладелецФормы <> Неопределено Тогда
        // Обращаемся к коллекции данных формы владельца
        // Обратите внимание: ВладелецФормы.Объект - это путь к данным документа на форме
        ВладелецФормы.Объект.Товары.Очистить();
        
        // Устанавливаем признак того, что форма документа изменена
        ВладелецФормы.Модифицированность = Истина;
    КонецЕсли;
    
КонецПроцедуры

Важный нюанс: работа с табличной частью на клиенте через ВладелецФормы ограничена возможностями коллекции ДанныеФормыКоллекция. Вы можете добавлять, удалять или изменять строки, но вы не сможете использовать методы прикладного объекта, такие как запросы к базе данных или сложные расчеты, требующие контекста сервера.

Метод 3. Работа с данными на сервере через копирование

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

Разберем пример кода в форме внешней обработки:


&НаКлиенте
Процедура ЗаполнитьДокументНаСервере()
    
    // Получаем данные из формы владельца в локальную переменную
    ДокументДанныеФормы = ВладелецФормы.Объект;
    
    // Вызываем серверную процедуру обработки
    ОбработатьДанныеНаСервере(ДокументДанныеФормы);
    
    // Сообщаем форме владельца, что данные обновились
    КопироватьДанныеФормы(ДокументДанныеФормы, ВладелецФормы.Объект);
    ВладелецФормы.Модифицированность = Истина;
    
КонецПроцедуры

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

Рекомендации и частые ошибки

Разберем основные моменты, которые часто становятся причиной ошибок при реализации подобных задач:

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

Проанализировав все способы, можно сделать вывод: для простых манипуляций достаточно прямого обращения к ВладелецФормы.Объект на клиенте. Для сложных алгоритмов заполнения оптимальным будет использование ОписаниеОповещения с возвратом структуры параметров и последующей обработкой в коде самого документа.

← На главную