Как передать данные из одной управляемой формы в другую в 1С?

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

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

Проанализируем ситуацию: разработчик пытается создать форму для ввода адреса по частям (город, улица, дом). После нажатия кнопки данные должны объединяться в одну строку и передаваться в поле на основной форме. Однако при попытке объединить значения возникает ошибка: «Невозможно преобразовать значение к типу число».

Разбираем первоначальную ошибку: Реквизиты vs. Элементы формы

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

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


// НЕПРАВИЛЬНО
ЭтаФорма.Параметры.ПараметрГород = ЭтаФорма.Элементы.ПолеВводаГород;
...
СтрокаАдрес = ЭтаФорма.Параметры.ПараметрГород + ", ул. " + ЭтаФорма.Элементы.ПолеВводаУлица + ЭтаФорма.Элементы.ПолеВводаДом;

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

Кроме того, ошибка «Невозможно преобразовать значение к типу число» возникает, когда один из реквизитов (например, номер дома) имеет числовой тип. При попытке сложить строки с числом с помощью оператора + (конкатенации) платформа может пытаться выполнить арифметическое сложение, что приводит к ошибке преобразования типов. Чтобы этого избежать, числовые значения нужно явно преобразовывать в строку с помощью функции Строка().

Способ 1. Обмен данными через глобальное оповещение (Оповестить)

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

  1. Открытие дочерней формы

    В модуле основной формы создаем команду, которая просто открывает нашу форму для ввода адреса.

    
    &НаКлиенте
    Процедура ВвестиАдрес(Команда)
        ОткрытьФорму("Справочник.ОбъектыСтроительства.Форма.ФормаЭлемента"); 
    КонецПроцедуры
    
  2. Формирование и отправка данных из дочерней формы

    В дочерней форме по нажатию кнопки «Записать» мы собираем данные из реквизитов, формируем строку и отправляем оповещение. Обратите внимание, что здесь мы уже обращаемся к реквизитам (например, ЭтаФорма.ГородФорма), а не к элементам, и используем функцию Строка() для безопасного преобразования типов.

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

    Важный момент: после вызова метода Оповестить() форма не закрывается автоматически. Чтобы закрыть ее, необходимо явно вызвать команду Закрыть().

  3. Получение данных в основной форме

    Чтобы основная форма «услышала» сигнал, в ее модуле должна быть экспортная процедура-обработчик ОбработкаОповещения.

    
    &НаКлиенте
    Процедура ОбработкаОповещения(ИмяСобытия, Параметр, Источник) Экспорт
        // Проверяем имя события, чтобы реагировать только на нужные сигналы
        Если ИмяСобытия = "ЗаполнениеАдреса" Тогда
            // Устанавливаем полученное значение в реквизит "Адрес"
            Адрес = Параметр; 
            
            Сообщить("Адрес получен: " + Параметр);
        КонецЕсли;
    КонецПроцедуры
    

    Этот способ рабочий, но имеет недостатки: он создает неявные связи между формами. Любая открытая форма с обработчиком ОбработкаОповещения может перехватить сигнал, что иногда приводит к непредсказуемому поведению. Поэтому для сценария «вопрос-ответ» между двумя конкретными формами существует более предпочтительный метод.

Способ 2. Модальное открытие с ОписаниемОповещения (Рекомендуемый стандарт)

Этот метод является современным стандартом, используемым в Библиотеке стандартных подсистем (БСП). Для глубокого изучения подобных механизмов рекомендуем использовать справочник по методам БСП, где собрано множество примеров кода — также в работе поможет инструмент для отладки и оптимизации кода на управляемых формах. Он устанавливает явную и прочную связь между вызывающей и вызываемой формами. Логика работы становится прозрачной и управляемой.

  1. Вызов дочерней формы из основной

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

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

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

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

    Самое главное изменение — в команде «Записать» (или «ОК»). Вместо Оповестить() мы используем метод Закрыть(), передавая в него возвращаемое значение.

    
    &НаКлиенте
    Процедура КомандаОК(Команда)
        // Собираем адрес из реквизитов формы
        Адрес = СокрЛП(Регион) + ", " + СокрЛП(Город) + ", " + СокрЛП(Улица)+ ", " + СокрЛП(Дом);
        
        // Закрываем форму и передаем собранную строку в качестве результата
        Закрыть(Адрес);
    КонецПроцедуры
    
  3. Получение результата в основной форме

    Теперь в основной форме будет вызвана та самая процедура, которую мы указали в ОписаниеОповещения. Значение, переданное в метод Закрыть(), придет в первый параметр этой процедуры.

    
    &НаКлиенте
    Процедура ПослеВыбораАдреса(Результат, ДопПараметры) Экспорт
        // Если пользователь закрыл форму без выбора (нажал крестик), результат будет Неопределено
        Если Результат = Неопределено Тогда
            Возврат;
        КонецЕсли;
    
        // Присваиваем полученное значение реквизиту основной формы
        Адрес = Результат;
    КонецПроцедуры
    

Дополнительные советы и лучшие практики

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

← На главную