Как передать реквизит формы в процедуру общего модуля для изменения его значения

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

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

Анализ проблемы: почему прямое присваивание не всегда работает

Разберем ситуацию, когда у нас есть реквизит обработки ИмяФайла с типом Строка. Мы вызываем процедуру общего модуля, чтобы она нашла файл и записала путь в этот реквизит. В языке 1С параметры процедур могут передаваться двумя способами: по значению (с использованием ключевого слова Знач) и по ссылке (без него). Если мы передаем переменную в пределах одной процедуры или в синхронный вызов, изменение параметра внутри процедуры изменит и исходную переменную.

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

Решение 1. Использование функции вместо процедуры (синхронный подход)

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

Рассмотрим пример кода на форме:


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

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

Решение 2. Передача контейнера и имени реквизита (универсальный метод)

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

Рассмотрим, как это реализовать по шагам:

  1. В вызывающей процедуре мы передаем сам Объект (который всегда передается по ссылке как сложный тип данных) и строку с именем реквизита.
  2. В процедуре завершения (обратном вызове) мы обращаемся к объекту через квадратные скобки.

Пример реализации в общем модуле:


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

// Процедура обратного вызова
Процедура ВыборФайлаЗавершение(ВыбранныеФайлы, ДополнительныеПараметры) Экспорт
    
    Если ВыбранныеФайлы <> Неопределено Тогда
        // Используем динамическое обращение к свойству объекта
        ОбъектВладелец = ДополнительныеПараметры.Объект;
        ИмяСвойства    = ДополнительныеПараметры.ИмяПоля;
        
        ОбъектВладелец[ИмяСвойства] = ВыбранныеФайлы[0];
    КонецЕсли;
    
КонецПроцедуры

Почему это работает? Объект Объект на форме имеет тип ДанныеФормыСтруктура. В 1С объекты этого типа позволяют обращаться к своим свойствам не только через точку (Объект.ИмяФайла), но и по индексу (Объект["ИмяФайла"]). Поскольку сам объект в структуру передается как ссылка, изменения в нем сразу отображаются в интерфейсе формы.

Решение 3. Использование современных асинхронных вызовов (Async/Await)

Если вы работаете на платформе версии 8.3.18 и выше, мы настоятельно рекомендуем отказаться от ОписаниеОповещения в пользу механизмов Асинх и Ждать. Это позволяет писать асинхронный код в линейном стиле, сохраняя область видимости локальных переменных и прямой доступ к реквизитам формы.

Проанализируем пример современного подхода:


&НаКлиенте
Асинх Процедура КомандаЗаполнитьФайлАсинхронно(Команда)
    
    // Вызываем асинхронную функцию подбора
    ПутьКФайлу = Ждать ПолучитьПутьКФайлуАсинхронно();
    
    Если ПутьКФайлу <> Неопределено Тогда
        // Прямое присваивание в контексте формы
        Объект.ИмяФайла = ПутьКФайлу;
    КонецЕсли;
    
КонецПроцедуры

&НаКлиенте
Асинх Функция ПолучитьПутьКФайлуАсинхронно()
    
    Диалог = Новый ДиалогВыбораФайла(РежимДиалогаВыбораФайла.Открытие);
    Результат = Ждать Диалог.ВыбратьАсинх();
    
    Если Результат <> Неопределено Тогда
        Возврат Результат[0];
    КонецЕсли;
    
    Возврат Неопределено;
    
КонецФункции

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

Важные технические нюансы

При работе с реквизитами и параметрами следует учитывать еще несколько важных моментов:

Выяснив причину разрыва связи между переменной и ее значением в асинхронных вызовах, мы можем сделать вывод: для надежной работы в 1С 8.3 следует либо использовать возвращаемые значения функций, либо передавать контейнер (Объект/Форму) вместе со строковым именем нужного реквизита.

← На главную