Как передать новые параметры в уже открытую форму 1С?

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

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

Решение 1: Механизм оповещений (рекомендуемый способ)

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

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

Шаг 1. Настройка формы-приемника (форма элемента справочника)

Форма, которая должна получать новые параметры, должна сначала сообщить системе, что она готова слушать определенные оповещения. Это делается с помощью подписки.

  1. В модуле формы элемента справочника в процедуре ПриСозданииНаСервере нужно подключить обработчик оповещения. Это делается с помощью метода ПодключитьОбработчикОповещения.

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

    
    &НаКлиенте
    // Важно: процедура должна быть экспортной!
    Процедура ОбработатьНовуюСтроку(ИмяСобытия, Параметр, Источник) Экспорт
        // ИмяСобытия - "ВыборНовогоКодаСтроки"
        // Параметр - это те данные, которые нам передали (например, структура с номером строки)
        // Источник - форма, которая отправила оповещение (если был указан)
    
        Если Параметр <> Неопределено И ТипЗнч(Параметр) = Тип("Структура") Тогда
            Если Параметр.Свойство("НомерСтроки") Тогда
                НовыйНомерСтроки = Параметр.НомерСтроки;
                // Здесь ваш код для активации строки с номером НовыйНомерСтроки
                // Например: Элементы.Товары.ТекущаяСтрока = Товары[НовыйНомерСтроки - 1].ПолучитьИдентификатор();
                Сообщить("Активирована строка: " + НовыйНомерСтроки);
            КонецЕсли;
        КонецЕсли;
    КонецПроцедуры
    
  3. Важный момент: хорошей практикой является отключение обработчика при закрытии формы, чтобы избежать "утечек" памяти. Это делается в событии ПриЗакрытии.

    
    &НаКлиенте
    Процедура ПриЗакрытии(ЗавершениеРаботы)
        ОтключитьОбработчикОповещения("ОбработатьНовуюСтроку");
    КонецПроцедуры
    

Шаг 2. Отправка оповещения из формы-источника (отчет)

Теперь в форме отчета, откуда мы хотим передать данные, нужно вызвать метод Оповестить.


// Предположим, в отчете мы определили, что нужно активировать строку с номером 5
ДанныеДляПередачи = Новый Структура;
ДанныеДляПередачи.Вставить("НомерСтроки", 5);

// Отправляем оповещение с именем "ВыборНовогоКодаСтроки" и передаем наши данные
Оповестить("ВыборНовогоКодаСтроки", ДанныеДляПередачи);

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

Решение 2: Комбинированный подход для универсальности

Механизм оповещений прекрасен, но у него есть особенность: он работает только для уже открытых форм. А что, если формы еще нет? Нам нужен код, который сработает в обоих случаях: и когда форма закрыта, и когда она уже открыта. Для этого объединим вызов ОткрытьФорму и Оповестить.

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

Шаг 1. Модификация кода в форме-источнике (отчет)


// Готовим параметры и для открытия, и для оповещения
ДанныеДляОткрытия = Новый Структура;
ДанныеДляОткрытия.Вставить("Ключ", СсылкаНаЭлемент); // Ссылка на элемент справочника
ДанныеДляОткрытия.Вставить("НомерСтроки", 5);

// Сначала посылаем оповещение. Если форма открыта, она его обработает.
Оповестить("ВыборНовогоКодаСтроки", ДанныеДляОткрытия);

// Затем вызываем ОткрытьФорму.
// Если форма закрыта, она откроется и получит параметры.
// Если форма открыта (с тем же КлючомУникальности), она просто активируется.
ОткрытьФорму("Справочник.Номенклатура.Форма.ФормаЭлемента", ДанныеДляОткрытия, , ДанныеДляОткрытия.Ключ);

Шаг 2. Модификация кода в форме-приемнике (форма справочника)

Чтобы этот универсальный код работал, нам нужно обрабатывать получение нового номера строки в двух местах:

  1. При первичном открытии (в процедуре ПриСозданииНаСервере или ПриОткрытии).
  2. При получении оповещения (в нашем обработчике ОбработатьНовуюСтроку).

Чтобы не дублировать код, вынесем логику в отдельную процедуру.


// В модуле формы элемента справочника

&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
    ПодключитьОбработчикОповещения("ОбработатьНовуюСтроку", "ВыборНовогоКодаСтроки");

    // Обрабатываем параметры при первом открытии
    Если Параметры.Свойство("НомерСтроки") Тогда
        ОбработатьНовыйНомерСтрокиНаСервере(Параметры.НомерСтроки);
    КонецЕсли;
КонецПроцедуры

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

&НаКлиенте
Процедура ОбработатьНовыйНомерСтрокиНаКлиенте(Номер)
    // Общая логика активации строки на клиенте
    Сообщить("Активирована строка: " + Номер);
    // ... ваш код
КонецПроцедуры

&НаСервере
Процедура ОбработатьНовыйНомерСтрокиНаСервере(Номер)
    // Общая логика на сервере, если она нужна при открытии
    // ... ваш код
КонецПроцедуры

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

Решение 3: Использование формы-владельца

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

Шаг 1. Открытие формы с указанием владельца

В форме отчета при открытии формы элемента передаем в качестве третьего параметра ЭтаФорма.


// В форме отчета
ТекПараметры = Новый Структура("Ключ", СсылкаНаЭлемент);
ОткрытьФорму("Справочник.ВашСправочник.Форма.ФормаЭлемента", ТекПараметры, ЭтаФорма);

Шаг 2. Получение данных от владельца в форме-приемнике

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

Важно: стандартные Параметры формы в событии ПриПовторномОткрытии не обновляются. Они остаются такими же, какими были при первом открытии. Именно поэтому нам и нужен "обходной путь" через владельца.


// В модуле формы элемента справочника

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

Этот метод создает сильную связь между формами, что снижает универсальность кода. Однако для локальных задач "один-к-одному" он вполне рабочий и понятный.

← На главную