Как передать выбранные данные между формами в 1С 8.3, если они не связаны отношениями владелец-подчиненный?

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

В разработке на платформе 1С:Предприятие 8.3 (управляемые формы) часто возникает задача интерактивного взаимодействия между различными окнами. Типичный сценарий: на основной форме (например, «Рабочий стол») расположены две таблицы. Из первой таблицы мы открываем форму подбора, чтобы уточнить количество или цену товара, а результат должны поместить во вторую таблицу, которая формально не является «родителем» или «владельцем» для окна подбора. Разберем детально, как реализовать такую передачу данных, используя стандартные механизмы платформы.

Анализ проблемы и выбор стратегии

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

Для решения этой задачи в 1С существует три основных способа:

  1. Использование механизма «Оповещение о выборе» (стандартный путь для подборов).
  2. Широковещательное оповещение через метод Оповестить() (гибкий путь для несвязанных форм).
  3. Использование описания оповещения (Callback) (современный и наиболее надежный программный метод).

Способ 1: Стандартный механизм «ОповеститьОВыборе»

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

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


&НаКлиенте
Процедура ТаблицаОстаткиВыбор(Элемент, ВыбраннаяСтрока, Поле, СтандартнаяОбработка)
    СтандартнаяОбработка = Ложь; // Отменяем стандартное действие
    
    // Подготавливаем параметры для открытия формы подбора
    ПараметрыФормы = Новый Структура;
    ПараметрыФормы.Вставить("Товар", Элементы.ТаблицаОстатки.ТекущиеДанные.Товар);
    ПараметрыФормы.Вставить("Цена", Элементы.ТаблицаОстатки.ТекущиеДанные.Цена);
    
    // Открываем форму, указывая Владельцем ТЕКУЩУЮ ФОРМУ (ЭтаФорма)
    // Это критически важно для работы ОбработкаВыбора
    ОткрытьФорму("Обработка.МояОбработка.Форма.ФормаПодбора", ПараметрыФормы, ЭтаФорма);
КонецПроцедуры

Теперь рассмотрим, как передать данные обратно из формы подбора при нажатии кнопки «ОК» или «Перенести»:


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

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


&НаКлиенте
Процедура ОбработкаВыбора(ВыбранноеЗначение, ИсточникВыбора)
    // Проверяем, что к нам пришла именно наша структура
    Если ТипЗнч(ВыбранноеЗначение) = Тип("Структура") И ВыбранноеЗначение.Свойство("Товар") Тогда
        // Добавляем данные во ВТОРУЮ таблицу (неподчиненную)
        НоваяСтрока = Объект.ТаблицаВыбранныеТовары.Добавить();
        ЗаполнитьЗначенияСвойств(НоваяСтрока, ВыбранноеЗначение);
    КонецЕсли;
КонецПроцедуры

Способ 2: Широковещательное оповещение через «Оповестить»

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

В форме подбора (отправитель):


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

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


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

Способ 3: Использование ОписанияОповещения (Callback)

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

Суть метода: при открытии формы мы сразу передаем ей «адрес» процедуры, которую нужно выполнить после закрытия окна подбора. Посмотрим на пример реализации в основной форме:


&НаКлиенте
Процедура ОткрытьПодборСУмнымВозвратом()
    // 1. Создаем описание оповещения, указывая имя экспортной (!) процедуры
    ОповещениеОЗакрытии = Новый ОписаниеОповещения("ПослеЗакрытияФормыПодбора", ЭтаФорма);
    
    // 2. Открываем форму, передавая оповещение в 7-й параметр
    ОткрытьФорму("Обработка.МояОбработка.Форма.ФормаПодбора", , ЭтаФорма, , , , ОповещениеОЗакрытии);
КонецПроцедуры

&НаКлиенте
// Процедура ДОЛЖНА БЫТЬ ЭКСПОРТНОЙ
Процедура ПослеЗакрытияФормыПодбора(Результат, ДополнительныеПараметры) Экспорт
    Если Результат <> Неопределено Тогда
        // Результат — это то, что мы передали в Закрыть() в форме подбора
        НоваяСтрока = Объект.ТаблицаВыбранныеТовары.Добавить();
        ЗаполнитьЗначенияСвойств(НоваяСтрока, Результат);
    КонецЕсли;
КонецПроцедуры

В форме подбора нам достаточно просто вызвать метод Закрыть() с передаваемым значением:


&НаКлиенте
Процедура КнопкаОК(Команда)
    Результат = Новый Структура("Товар, Цена", Объект.Товар, Объект.Цена);
    Закрыть(Результат); // Параметр попадет в процедуру ПослеЗакрытияФормыПодбора
КонецПроцедуры

Важные нюансы работы с данными

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

  1. Форма подбора записывает данные в базу данных (например, в документ или регистр сведений).
  2. После записи вызывается метод ОповеститьОбИзменении(Тип("СправочникСсылка.Номенклатура")) или аналогичный для вашего объекта.
  3. Основная форма автоматически «перечитает» данные из базы и обновит список.

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

Рассмотренные методы покрывают 100% потребностей при взаимодействии управляемых форм. Выбор конкретного способа зависит от сложности вашей конфигурации: для простых подборов используйте ОповеститьОВыборе, для сложных систем с множеством окон — ОписаниеОповещения.

← На главную