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

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

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

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

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

Для реализации этого механизма выполним следующие действия:

  1. В форме документа вызовем открытие формы подбора, указав текущую форму в качестве владельца и передав параметр ЗакрыватьПриВыборе = Ложь.
  2. В форме подбора настроим событие выбора элемента динамического списка.
  3. В форме документа перехватим выбранные данные с помощью предопределенного события ОбработкаВыбора.

Посмотрим на пример открытия формы подбора из модуля формы документа:


&НаКлиенте
Процедура ПодборНоменклатуры(Команда)
    ПараметрыПодбора = Новый Структура;
    ПараметрыПодбора.Вставить("ЗакрыватьПриВыборе", Ложь);
    ПараметрыПодбора.Вставить("МножественныйВыбор", Истина);
    
    // Владельцем формы указываем "ЭтаФорма"
    ОткрытьФорму("ОбщаяФорма.ФормаПодбора", ПараметрыПодбора, ЭтаФорма);
КонецПроцедуры

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


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

В модуле формы документа перехватываем переданную структуру в процедуре ОбработкаВыбора:


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

Способ 2. Пакетный перенос данных через описание оповещения о закрытии

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

Для этого используется асинхронный механизм ОписаниеОповещения:


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

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

В форме подбора на стороне клиента при нажатии кнопки переноса данных вызывается метод Закрыть с передачей сформированного массива:


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

Почему возникает блокировка документа и как ее устранить?

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

Причина 1: Необоснованное использование РеквизитФормыВЗначение на сервере.

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

Причина 2: Изменение коллекции на клиенте без записи.

При добавлении строк в коллекцию Объект.Товары форма переходит в состояние Модифицированность = Истина. Это нормальное штатное поведение 1С — документ помечается как измененный, и платформа ставит блокировку от одновременного редактирования другими сеансами. Если документ закрыть без сохранения, изменения сбрасываются, но при некорректном завершении серверных вызовов блокировка может сниматься с задержкой.

Рекомендации по заполнению табличной части:

  1. Если не требуется сложных серверных расчетов (пересчет цен, скидок), добавляем строки напрямую в реквизит формы Объект.Товары на клиенте через метод Добавить().
  2. Если заполнение выполняется на сервере, не следует преобразовывать реквизит формы в ДокументОбъект. Используйте работу непосредственно с коллекцией ДанныеФормыКоллекция (доступна через Объект.Товары на сервере формы) или метод Загрузить().

Посмотрим на пример корректной пакетной загрузки данных на сервере без преобразования объекта:


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

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

← На главную