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

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

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

Проблема: идентификатор ссылки вместо идентификатора формы

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


// Неправильный подход!
ИдентификаторФормы = ХарактеристикаСсылка.УникальныйИдентификатор();

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

В чем разница: УИД объекта и УИД формы

Чтобы избежать путаницы, важно четко понимать различие между двумя типами уникальных идентификаторов в 1С.

  1. Уникальный идентификатор объекта (ссылки). Получается методом СсылкаНаОбъект.УникальныйИдентификатор(). Это постоянный, глобально уникальный идентификатор (GUID), который однозначно определяет запись в информационной базе. Он хранится вместе с данными и не меняется на протяжении всей жизни объекта.
  2. Уникальный идентификатор формы. Получается через свойство ЭтаФорма.УникальныйИдентификатор. Это временный идентификатор, который присваивается конкретному экземпляру открытой формы в клиентском сеансе. Если вы откроете одну и ту же характеристику в двух разных окнах, у каждой из этих форм будет свой, уникальный УИД. Как только форма закрывается, ее идентификатор перестает существовать.

Типовые файловые операции требуют именно идентификатор экземпляра формы, а не объекта данных.

Правильное решение: как получить УИД формы

Получить идентификатор текущей формы, из которой выполняется код, очень просто. Для этого нужно обратиться к свойству ЭтаФорма, которое доступно в модуле любой управляемой формы:


// Правильный подход
ИдентификаторТекущейФормы = ЭтаФорма.УникальныйИдентификатор;

Этот идентификатор и нужно передавать в параметры функций работы с файлами. Чаще всего код для пакетной загрузки файлов размещают в форме внешней обработки. Соответственно, именно УИД формы этой обработки и будет использоваться.

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


&НаКлиенте
Процедура ЗагрузитьФайлы()

    // ... код получения ссылки на характеристику, пути к картинке и т.д.
    Характеристика = ...;
    ПутьККартинке = ...;

    // Получаем УИД ТЕКУЩЕЙ формы, из которой вызываем операцию
    ИдентификаторФормы = ЭтаФорма.УникальныйИдентификатор; 

    ДополнительныеПараметры = Новый Структура;
    ДополнительныеПараметры.Вставить("ВладелецФайла", Характеристика);
    ДополнительныеПараметры.Вставить("ИдентификаторФормы", ИдентификаторФормы); // Передаем правильный УИД
    ДополнительныеПараметры.Вставить("ПолноеИмяФайла", ПутьККартинке);
    // ... другие параметры
            
    РаботаСФайламиСлужебныйКлиент.ДобавитьФайлыРасширениеПредложено(Истина, ДополнительныеПараметры);

КонецПроцедуры

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

Зачем вообще нужен идентификатор формы?

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

1. Привязка к временному хранилищу

Когда вы добавляете файл с клиента, он не сразу попадает в базу данных. Сначала он передается на сервер и помещается во временное хранилище. Это специальная область памяти на сервере для временного хранения данных между клиентскими и серверными вызовами. Чтобы сервер "знал", какой клиентской форме принадлежит этот файл, он помечается уникальным идентификатором этой формы. Это как бирка на чемодане в камере хранения.

2. Автоматическая очистка временного хранилища

Благодаря этой "бирке", система может автоматически очищать за собой мусор. Когда вы закрываете форму, платформа 1С находит все данные во временном хранилище, связанные с УИД этой закрытой формы, и удаляет их. Это предотвращает утечки памяти на сервере и его "замусоривание" ненужными файлами.

3. Механизм обратных вызовов (Оповещений)

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

Альтернативный и более надежный подход

Автор темы для решения своей задачи адаптировал внутреннюю, "служебную" процедуру РаботаСФайламиСлужебныйКлиент.ДобавитьФайлыРасширениеПредложено. Он добавил в структуру параметров свой ключ "ПолноеИмяФайла", чтобы обойти интерактивный диалог выбора файла. Этот подход работает, но имеет риски: внутренние (служебные) процедуры не являются частью публичного API, и их логика или параметры могут измениться при обновлении конфигурации, что сломает вашу доработку.

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

  1. На клиенте: помещаем файл во временное хранилище с явным указанием УИД нашей формы.
  2. На клиенте: вызываем серверную процедуру и передаем ей адрес, полученный на первом шаге.
  3. На сервере: используем публичную функцию API, например РаботаСФайлами.ДобавитьФайл, чтобы создать запись о присоединенном файле.

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


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

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

&НаСервере
Функция ДобавитьПрисоединенныйФайлНаСервере(Адрес, ИмяФайла, ВладелецФайла)
    
    ПараметрыФайла = Новый Структура;
    ПараметрыФайла.Вставить("АдресВоВременномХранилище", Адрес);
    ПараметрыФайла.Вставить("ИмяБезРасширения", РаботаСФайлами.ИмяФайлаБезРасширения(ИмяФайла));
    ПараметрыФайла.Вставить("РасширениеБезТочки", РаботаСФайлами.РасширениеФайла(ИмяФайла));
    ПараметрыФайла.Вставить("ВладелецФайла", ВладелецФайла);
    
    Возврат РаботаСФайлами.ДобавитьФайл(ПараметрыФайла);
    
КонецФункции

В итоге: всегда используйте ЭтаФорма.УникальныйИдентификатор для получения идентификатора формы. Помните, что он необходим для корректной работы асинхронных операций и управления временным хранилищем. Для долгосрочной поддержки доработок старайтесь опираться на публичные API-функции стандартных подсистем, а не на их внутренние механизмы. Для поиска и изучения таких методов пригодится справочник по методам БСП с примерами использования.

← На главную