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

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

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

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

Архитектурная причина: почему у элемента формы нет значения на клиенте

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

  1. Элементы формы (например, ПолеФормы) — это исключительно визуальные компоненты отображения на стороне тонкого клиента. Они отвечают за отрисовку, реакцию на действия пользователя и оформление, но не хранят данные внутри себя.
  2. Данные формы (реквизиты формы, объект ДанныеФормыСтруктура, коллекции) — это структуры данных, которые передаются между клиентом и сервером и хранят реальные значения полей.
  3. Свойство ПутьКДанным — связывает элемент с конкретным реквизитом. Ради оптимизации клиент-серверного трафика метаданные формы урезаны на клиенте, поэтому свойство ПутьКДанным доступно только на сервере (в директивах &НаСервере или &НаСервереБезКонтекста).

Попытка присвоить значение напрямую элементу вида Элемент.Значение = Рез; вызовет исключение времени выполнения, так как такого свойства не существует в объектной модели управляемой формы.

Основное решение: передача элемента формы в качестве владельца формы выбора

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

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

Разберем по шагам реализацию данного механизма на примере поля ввода со строковым значением и множественным выбором из справочника:

  1. В обработчике НачалоВыбора отключаем стандартную обработку и открываем форму выбора, передав текущий Элемент в качестве владельца. Обязательно передаем параметр РежимВыбора = Истина, чтобы форма открывалась именно для подбора данных.
  2. В обработчике события элемента ОбработкаВыбора перехватываем выбранные данные (массив ссылок), преобразуем их в строку и оставляем флаг СтандартнаяОбработка = Истина — платформа сама запишет преобразованное значение в связанный реквизит формы.

Посмотрим на пример программного кода:


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

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

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

Альтернативное решение: определение пути к данным на сервере через колбэк

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

В этом случае передавать сам объект элемента формы между клиентом и сервером нельзя — на сервер передается строковое имя элемента Элемент.Имя, а обращение к метаданным связи выполняется в серверном контексте.

Проанализируем пример кода с передачей управления на сервер:


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

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

&НаСервере
Процедура ЗаписатьЗначениеВРеквизитНаСервере(ИмяЭлемента, ЗначениеДляЗаписи)
    ЭлементФормы = Элементы[ИмяЭлемента];
    ПутьКДанным = ЭлементФормы.ПутьКДанным;
    
    // Если путь не содержит составных частей через точку, это простой реквизит формы
    Если СтрНайти(ПутьКДанным, ".") = 0 Тогда
        ЭтаФорма[ПутьКДанным] = ЗначениеДляЗаписи;
    Иначе
        // Для составных путей (например, Объект.РеквизитШапки)
        ЧастиПути = СтрРазделить(ПутьКДанным, ".");
        Если ЧастиПути.Количество() = 2 Тогда
            ЭтаФорма[ЧастиПути[0]][ЧастиПути[1]] = ЗначениеДляЗаписи;
        КонецЕсли;
    КонецЕсли;
КонецПроцедуры

Особенности дополнительных реквизитов (БСП)

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

  1. Совпадение имен: подсистема БСП при создании элементов дополнительных реквизитов генерирует для них имена элементов и реквизитов формы по единому шаблону (например, с префиксом ДополнительныйРеквизитЗначение_...). В этом частном случае обращение вида ЭтаФорма[Элемент.Имя] = Значение; технически работает, так как имена совпадают.
  2. Обновление зависимостей: при программной записи строкового значения напрямую в реквизит формы типовая интерактивная логика БСП не узнает об изменении. Если для этого дополнительного реквизита настроены условия видимости, доступности или обязательности заполнения, на клиенте следует вызвать метод обновления зависимостей:
    
    УправлениеСвойствамиКлиент.ОбновитьЗависимостиДополнительныхРеквизитов(ЭтаФорма);
    
  3. Запись в табличные части: если элемент формы привязан к строке таблицы (путь к данным вида Объект.ТабличнаяЧасть.ИмяКолонки), на клиенте не требуется обращаться к метаданным. Достаточно получить текущую строку через свойство таблицы: Элементы.ИмяТаблицы.ТекущиеДанные[ИмяКолонки] = Значение;.

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

← На главную