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