Как правильно передавать параметры между управляемыми формами в 1С:Предприятии и получать результаты их отработки?

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

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

Наш вопрос состоит из двух основных частей:

  1. Как передать параметры от ФормыСписка (вызывающей формы) к ФормеДокумента (открываемой форме)?
  2. Как получить параметры отработки ФормыДокумента для передачи обратно в ФормуСписка после её закрытия?

Прежде чем мы углубимся в детали, сразу отметим, что для таких задач категорически не рекомендуются


ПараметрыСеанса
и

Константы
. Эти механизмы предназначены для хранения глобальных, долгоживущих данных или фиксированных значений, но не для временной и локальной передачи информации между конкретными экземплярами форм. Использование их для этой цели может привести к трудноотлаживаемым ошибкам, конфликтам данных при одновременной работе нескольких пользователей или форм, а также к общему снижению качества кода.

1. Передача параметров от вызывающей формы к открываемой форме

Для передачи данных из ФормыСписка в ФормуДокумента при ее открытии мы будем использовать метод


ОткрытьФорму()
, который позволяет передать параметры в виде структуры.

Шаг 1: Формирование и передача параметров в вызывающей форме

В ФормеСписка (или любой другой форме, из которой вы открываете новую форму), необходимо сформировать структуру с параметрами, которые вы хотите передать. Затем эта структура передается вторым аргументом метода


ОткрытьФорму()
.

Рассмотрим пример, когда нам нужно открыть форму документа и передать в неё некие


пПервыйПараметр
и

пВторойПараметр
:


// В модуле формы-списка (например, в обработчике команды)
&НаКлиенте
Процедура ОткрытьФормуДокументаСПараметрами(Команда)
    // Предположим, у нас есть некоторые значения для передачи
    ПередаваемыйПервыйПараметр  = "Некое строковое значение";
    ПередаваемыйВторойПараметр = Новый Дата(2023, 1, 1);

    // Создаем структуру для передачи параметров
    // Ключи структуры (строки "ПервыйПараметр", "ВторойПараметр")
    // станут именами свойств в коллекции Параметры открываемой формы.
    П = Новый Структура("ПервыйПараметр, ВторойПараметр", ПередаваемыйПервыйПараметр, ПередаваемыйВторойПараметр);

    // Открываем форму документа, передавая ей структуру с параметрами
    ОткрытьФорму("Документ.МойДокумент.Форма.ФормаДокумента", П);
КонецПроцедуры

Мы создаем


Новый Структура()
, указывая имена параметров через запятую в первой строке и их значения во второй. Это удобный способ создать структуру с несколькими свойствами сразу. В нашем случае, открывается форма документа

"Документ.МойДокумент.Форма.ФормаДокумента"
.

Шаг 2: Получение и использование параметров в открываемой форме

В открываемой ФормеДокумента (или любой другой форме, которая принимает параметры), переданные значения будут доступны через свойство формы


Параметры
. Обработка этих параметров обычно происходит в процедуре

ПриСозданииНаСервере
, которая вызывается при создании экземпляра формы на сервере.

Посмотрим на пример из обсуждения, как мы можем получить эти параметры:


// В модуле формы документа
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
    // Инициализация формы или её реквизитов на основе переданных параметров

    // Проверяем, были ли переданы параметры
    Если Параметры.Свойство("ПервыйПараметр") Тогда
        // Сохраняем значение в реквизит формы, чтобы использовать его в других процедурах
        ЭтотОбъект.ПервыйПараметрФормы = Параметры.ПервыйПараметр;
        // Можем сразу использовать параметр, например, для инициализации поля
        Сообщить("Получен ПервыйПараметр: " + ЭтотОбъект.ПервыйПараметрФормы);
    КонецЕсли;

    Если Параметры.Свойство("ВторойПараметр") Тогда
        // Сохраняем значение в реквизит формы
        ЭтотОбъект.ВторойПараметрФормы = Параметры.ВторойПараметр;
        Сообщить("Получен ВторойПараметр: " + ЭтотОбъект.ВторойПараметрФормы);
    КонецЕсли;

    // ... дальнейшая логика инициализации формы ...

    // Если форма открывается для нового документа,
    // а нам нужно инициализировать его на основе параметров,
    // то можно сделать следующее:
    Если Объект.ЭтоНовый() Тогда
        Если Параметры.Свойство("ТипОперации") Тогда
            Объект.ТипОперации = Параметры.ТипОперации;
        КонецЕсли;
        // и т.д. для других реквизитов объекта документа
    КонецЕсли;

КонецПроцедуры

В этом примере мы видим, как важно использовать


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

ЭтотОбъект.ПервыйПараметрФормы
), чтобы он был доступен во всех других процедурах и функциях модуля формы, как клиентских, так и серверных, в течение всего жизненного цикла формы.

Чтобы реквизит формы был доступен, его необходимо предварительно создать в конфигураторе для данной формы. Вы можете добавить реквизит формы с нужным типом (например, "Строка", "Дата", "СправочникСсылка.МойСправочник" и т.д.), и затем присваивать ему значения в


ПриСозданииНаСервере
. После этого к этому реквизиту можно будет обращаться как

ЭтотОбъект.ИмяВашегоРеквизита
из любого метода формы.

2. Получение параметров отработки от формы-документа в форму-списка

Для возврата результатов работы из закрываемой ФормыДокумента обратно в вызвавшую ее ФормуСписка, наиболее правильным и асинхронным способом является использование механизма


ОписаниеОповещения
.

Шаг 1: Создание ОписаниеОповещения в вызывающей форме

При открытии ФормыДокумента из ФормыСписка, мы передаем объект


ОписаниеОповещения
в качестве одного из аргументов метода

ОткрытьФорму()
. Этот объект содержит информацию о том, какую процедуру и в каком модуле нужно вызвать после закрытия открываемой формы.

Разберем пример из сообщения 3:


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

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

    // Открываем форму, передавая в неё параметры и ОписаниеОповещения.
    // Используем полные параметры метода ОткрытьФорму:
    // 1. Имя формы
    // 2. Параметры открываемой формы (для её инициализации)
    // 3. Владелец формы (обычно ЭтотОбъект, чтобы открываемая форма знала, кто ее вызвал)
    // 4. УникальныйИдентификатор (необязательно, если не нужен)
    // 5. Окно (необязательно, если не нужен)
    // 6. КлючУникальности (необязательно)
    // 7. ОписаниеОповещения (наш объект ОбработкаВыбора)
    // 8. РежимОткрытияОкнаФормы (например, блокировать весь интерфейс)
    ОткрытьФорму("Справочник.МойСправочник.Форма.ФормаВыбора", Парам, ЭтотОбъект,,,, ОбработкаВыбора, РежимОткрытияОкнаФормы.БлокироватьВесьИнтерфейс);
КонецПроцедуры

// Процедура-обработчик, которая будет вызвана после закрытия формы выбора
// Она должна быть Экспортной, если вызывается извне.
// Первый параметр - результат, переданный закрывающейся формой.
// Второй параметр - дополнительные параметры, которые мы передали при создании ОписаниеОповещения.
&НаКлиенте
Процедура ВыгрузкаДокументаКонец(МойЭлемент, ПараметрыВыгрузки) Экспорт
    // МойЭлемент - это то, что передала закрывающаяся форма через ОповеститьОВыборе() или Закрыть().
    // ПараметрыВыгрузки - это Парам, которые мы создали в процедуре Выгрузить.

    Если МойЭлемент = Неопределено Тогда
        Сообщить("Выбор отменен или форма закрыта без результата.");
        Возврат;
    КонецЕсли;

    Сообщить("Выбран элемент: " + МойЭлемент + ". Режим выбора: " + ПараметрыВыгрузки.РежимВыбора);
    // Здесь мы можем обновить список, выполнить какие-либо действия
    // например, записать выбранный элемент в реквизит или обновить табличную часть.
    // Если требуется обновить данные в списке:
    // ОбновитьЭлементы();
КонецПроцедуры

В этом примере мы видим, как создается


ОписаниеОповещения
с указанием процедуры

ВыгрузкаДокументаКонец
в текущем объекте

ЭтотОбъект
. Дополнительные параметры

Парам
будут доступны в обработчике. Затем мы передаем этот объект

ОбработкаВыбора
в метод

ОткрытьФорму()
.

Шаг 2: Возврат результатов из закрываемой формы

В ФормеДокумента (или любой другой форме, которую вы открыли и из которой нужно вернуть результат), когда работа завершена и результат готов, мы используем метод


ОповеститьОВыборе()
или

Закрыть()
для возврата значения. Метод

Закрыть()
имеет перегрузку, позволяющую передать результат. Если форма была открыта с

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

Продолжим пример, как ФормаДокумента может вернуть значение:


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

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

    // После оповещения можно закрыть форму.
    // Если передать значение в Закрыть(), то оно будет передано в оповещение.
    // Закрыть(ВыбранноеЗначение);
КонецПроцедуры

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

После вызова


ОповеститьОВыборе(ВыбранноеЗначение)
или

Закрыть(ВыбранноеЗначение)
, процедура

ВыгрузкаДокументаКонец
в ФормеСписка будет вызвана, и

ВыбранноеЗначение
будет передано в её первый параметр

МойЭлемент
.

3. Почему не стоит использовать ПараметрыСеанса и Константы

Как мы уже упоминали, использование


ПараметровСеанса
и

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

  1. ПараметрыСеанса:
    • Глобальная область видимости:
      
      ПараметрыСеанса
      
      доступны на протяжении всего сеанса работы пользователя. Это означает, что если пользователь откроет несколько форм, каждая из которых пытается использовать один и тот же параметр сеанса, возникнут конфликты, и данные могут быть перезаписаны или считаны некорректно.
    • Сложности отладки: Отследить, кто и когда изменил параметр сеанса, становится крайне сложно, особенно в многопользовательских системах или при работе с множеством открытых окон.
    • Ненужная нагрузка: Для кратковременной передачи данных создается избыточная нагрузка на систему, поскольку параметры сеанса сохраняются и поддерживаются сервером.
    • Нарушение инкапсуляции: Формы становятся сильно связанными через глобальные переменные, что затрудняет их повторное использование и поддержку.
  2. Константы:
    • Фиксированные значения:
      
      Константы
      
      предназначены для хранения фиксированных, редко изменяющихся значений, доступных всем пользователям и всей системе (например, основная организация, курс валюты по умолчанию). Они вообще не подходят для динамической передачи параметров между формами.
    • Изменения требуют привилегий: Изменение констант обычно требует административных прав и приводит к записи в базу данных, что абсолютно неприемлемо для временных параметров.

Всегда отдавайте предпочтение прямым механизмам передачи параметров, таким как аргументы методов


ОткрытьФорму()
и

ОписаниеОповещения
.

4. Важные аспекты безопасности и универсальности

Вопрос, поднятый в обсуждении, очень важен: "А если документ будет открыт не из форм списка, а из какого-нибудь реквизита или по навигационной ссылке или из избранного. Логика безопасности не нарушится?"

Мы должны всегда помнить, что форма может быть открыта не только из того места, где мы ожидаем передачу параметров. Пользователь может:

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

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

Применяя описанные подходы, мы создаем гибкие, надежные и легко поддерживаемые механизмы взаимодействия между формами в 1С:Предприятии, избегая при этом распространенных ошибок и "слома стандартной обработки", которая неизбежно приводит к проблемам в долгосрочной перспективе.

← На главную