Как обратиться из модуля объекта документа к процедуре формы или ее элементам

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

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

Почему прямое обращение невозможно?

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

Модуль формы — это программный слой, отвечающий за визуализацию и взаимодействие с пользователем. Элементы формы (кнопки, видимость колонок) существуют только в контексте открытого окна. Именно поэтому система «не видит» форму из объекта — их жизненные циклы разделены.

Решение 1: Использование реквизитов документа

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

Допустим, нам нужно записывать данные в регистр «Учет медикаментов» только если на форме включен режим работы с сериями. Выполним следующие шаги:

  1. Добавим в документ реквизит ПоказыватьСерии с типом Булево.
  2. На форме свяжем состояние кнопки или видимость колонки с этим реквизитом.
  3. В модуле объекта будем проверять значение этого реквизита.

Посмотрим на пример реализации логики переключения на форме:


&НаСервере
Процедура ПереключитьРежимСерий(Команда)
    // Инвертируем значение реквизита документа через данные формы
    Объект.ПоказыватьСерии = НЕ Объект.ПоказыватьСерии;
    
    // Управляем видимостью элементов в зависимости от реквизита
    Элементы.ГруппаСерии.Видимость = Объект.ПоказыватьСерии;
    Элементы.ТоварыСерияМедикамента.Видимость = Объект.ПоказыватьСерии;
КонецПроцедуры

Теперь в модуле объекта мы можем безопасно использовать это условие:


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

Решение 2: Анализ данных табличной части

Проанализируем ситуацию, когда добавление лишнего реквизита нежелательно. Часто логика «кнопки» на самом деле дублирует логику наличия данных. Если в документе заполнены серии, значит, нужно делать движения. Если серии пустые — движения не нужны.

Рассмотрим вариант кода, который проверяет заполненность данных непосредственно в цикле проведения. Это исключает необходимость обращения к интерфейсным элементам:


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

Использование метода ЗначениеЗаполнено() является универсальным и позволяет избежать ошибок, связанных с типами данных (строка, ссылка или число).

Решение 3: Использование «Дополнительных свойств»

Выясним, как передать информацию из формы в модуль объекта, если мы не хотим сохранять её в базе данных (то есть без создания реквизита). Для этого у любого объекта метаданных существует коллекция ДополнительныеСвойства. Это структура, которая живет только пока объект находится в оперативной памяти сервера во время транзакции записи.

Разберем по шагам, как это реализовать:

1. В модуле формы в предопределенной процедуре ПередЗаписьюНаСервере мы помещаем нужный нам флаг в объект:


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

2. В модуле объекта в процедуре ОбработкаПроведения мы считываем это значение:


Процедура ОбработкаПроведения(Отказ, РежимПроведения)
    НужноПисать = Ложь;
    Если ДополнительныеСвойства.Свойство("ЗаписыватьВРегистр") Тогда
        НужноПисать = ДополнительныеСвойства.ЗаписыватьВРегистр;
    КонецЕсли;

    Если НужноПисать Тогда
        // Логика формирования движений
    КонецЕсли;
КонецПроцедуры

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

Типичные ошибки при реализации

Проанализируем основные ошибки, которые совершают разработчики при попытке связать форму и объект:

Рекомендации по проектированию

Для создания чистого и надежного кода придерживайтесь следующих правил:

  1. Приоритет данных: Старайтесь строить логику проведения на основе данных в табличных частях (наличие номенклатуры определенного вида, заполненность реквизитов строк), а не на основе состояния кнопок.
  2. Валидация: Если для проведения документа критично наличие серии, используйте процедуру ОбработкаПроверкиЗаполнения в модуле объекта. Это позволит системе автоматически выдать предупреждение пользователю еще до начала транзакции проведения.
  3. Разделение ответственности: Форма должна только собирать данные и передавать их в объект. Вся бизнес-логика должна быть сосредоточена внутри объекта или в модуле менеджера.

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

← На главную