Как обратиться из общего серверного модуля к элементам управляемой формы и объекту в 1С

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

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

Архитектурные ограничения клиент-серверного взаимодействия

Выясним причину, по которой классическая цепочка «Модуль формы (Клиент) → Общий модуль (Клиент) → Общий модуль (Сервер)» не позволяет управлять элементами формы:

  1. Клиентская и серверная форма — разные сущности. В контексте тонкого клиента форма представляет собой клиентский интерфейсный объект УправляемаяФорма. На сервере существует ее серверный контекст. Между клиентом и сервером форма не сериализуется как единое целое.
  2. Невозможно передать форму с клиента на сервер в параметре процедуры. Попытка передать переменную ЭтаФорма из клиентской процедуры в функцию с директивой вызова сервера завершится системной ошибкой, так как тип УправляемаяФорма не входит в список сериализуемых типов данных.
  3. Доступ к незаписанному объекту. Пока новый элемент справочника или документ не записан в базу данных, его ссылки не существует. Получить доступ к данным объекта можно либо через реквизиты формы, либо преобразованием контекста серверной формы через РеквизитФормыВЗначение("Объект"), либо в предопределенных серверных событиях формы.

Вариант 1. Вызов общего модуля из серверных событий формы

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

В серверном контексте модуля формы ключевое слово ЭтотОбъект указывает на серверный экземпляр формы. Мы можем передать его в общий серверный модуль в качестве параметра. Рассмотрим пример вызова из модуля формы:


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

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


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

При возврате управления на клиент платформа автоматически синхронизирует состояние формы, и измененные свойства элементов (например, цвет фона) отобразятся у пользователя.

Вариант 2. Использование штатного механизма «СообщениеПользователю»

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

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


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

Важный момент: метод УстановитьДанные(Объект) автоматически связывает создаваемое сообщение с открытой формой редактируемого объекта даже в том случае, если этот объект еще ни разу не был записан в базу данных. В интерфейсе «Такси» платформа подсвечивает поле красным маркером без обязательного открытия классического нижнего окна сообщений.

Вариант 3. Полный отказ от дублирования кода через подписку на события

Если цель состоит в том, чтобы не вставлять вызовы проверок в модули сотен справочников и документов конфигурации, воспользуемся подпиской на события. Управляемые формы не имеют глобальных подписок, но при интерактивной записи объекта всегда срабатывает событие объекта ОбработкаПроверкиЗаполнения.

Разберем реализацию по шагам:

  1. Создаем в дереве метаданных новый объект ПодпискаНаСобытие.
  2. В поле Источник указываем составной тип из нужных документов и справочников (или типы ДокументОбъект, СправочникОбъект).
  3. В поле Событие выбираем ОбработкаПроверкиЗаполнения.
  4. В поле Обработчик указываем экспортную процедуру общего серверного модуля.

Код обработчика подписки в общем модуле:


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

Удаление имени реквизита из массива ПроверяемыеРеквизиты позволяет полностью отключить стандартные предупреждения платформы 1С и заменить их собственными текстами сообщений на любом требуемом языке без модификации кода в модулях форм.

← На главную