В современной разработке на платформе 1С:Предприятие 8.3 работа с мультимедийными данными, такими как логотипы организаций или фотографии товаров, является стандартной задачей. Однако начинающие разработчики часто сталкиваются с трудностями при попытке связать двоичные данные, хранящиеся в базе, с элементами управления на форме. Разберем по шагам, как правильно реализовать механизм выбора, сохранения и корректного отображения картинки в справочнике.
Для начала проанализируем ситуацию. Предположим, у нас есть справочник БлаготворительныеОрганизации. Для работы с изображениями нам понадобятся следующие реквизиты:
ХранилищеЗначения) — здесь будут физически храниться двоичные данные изображения в базе данных.Строка) — в этом реквизите мы будем хранить имя файла с расширением для информативности.На самой форме справочника нам необходимо создать реквизит формы (не путать с реквизитом объекта), который мы назовем Логотип. Его тип должен быть Строка. Именно этот строковый реквизит мы разместим на форме и установим ему вид Поле картинки. В нем будет храниться либо адрес временного хранилища (пока объект не записан), либо навигационная ссылка на данные в базе.
Рассмотрим подробнее процесс выбора файла пользователем. Для этого мы создадим команду на форме и соответствующую процедуру. Важно помнить, что в управляемом приложении работа с файловой системой на клиенте должна быть асинхронной. Выясним причину: это необходимо для работы в веб-клиенте и обеспечения отзывчивости интерфейса.
&НаКлиенте
Процедура ВыбратьЛоготип(Команда)
// Настройка диалога выбора файла
ДиалогОткрытия = Новый ДиалогВыбораФайла(РежимДиалогаВыбораФайла.Открытие);
ДиалогОткрытия.ПолноеИмяФайла = "";
ДиалогОткрытия.Фильтр = "Все картинки (*.bmp;*.jpg;*.jpeg;*.png;)|*.bmp;*.jpg;*.jpeg;*.png;";
ДиалогОткрытия.МножественныйВыбор = Ложь;
ДиалогОткрытия.Заголовок = "Выберите логотип организации";
// Подготовка описания оповещения для обработки выбора
ОписаниеОповещения = Новый ОписаниеОповещения("ПослеВыбораФайла", ЭтаФорма);
ДиалогОткрытия.Показать(ОписаниеОповещения);
КонецПроцедуры
После того как пользователь выбрал файл, нам нужно передать его данные с клиента на сервер. Напрямую записать файл в базу с клиента нельзя. Проанализируем ситуацию: сначала мы помещаем файл во временное хранилище, получаем уникальный адрес, и только потом, при записи объекта, переносим данные в основной реквизит Картинка.
&НаКлиенте
Процедура ПослеВыбораФайла(ВыбранныеФайлы, ДополнительныеПараметры) Экспорт
Если ВыбранныеФайлы = Неопределено Тогда
Возврат;
КонецЕсли;
ПутьКФайлу = ВыбранныеФайлы[0];
ОписаниеОповещения = Новый ОписаниеОповещения("ПослеПомещенияВХранилище", ЭтаФорма);
// Помещаем файл во временное хранилище, привязывая его к идентификатору формы
НачатьПомещениеФайла(ОписаниеОповещения, , ПутьКФайлу, Ложь, УникальныйИдентификатор);
КонецПроцедуры
&НаКлиенте
Процедура ПослеПомещенияВХранилище(Результат, Адрес, ВыбранноеИмяФайла, ДополнительныеПараметры) Экспорт
Если Не Результат Тогда
Возврат;
КонецЕсли;
// Сохраняем адрес временного хранилища в реквизит формы для отображения
Логотип = Адрес;
// Извлекаем имя файла для сохранения в реквизит объекта
ФайлИнфо = Новый Файл(ВыбранноеИмяФайла);
Объект.СсылкаНаКартинку = ФайлИнфо.Имя;
Модифицированность = Истина;
КонецПроцедуры
Теперь разберем, как данные попадают в базу. Основная работа происходит в обработчике ПередЗаписьюНаСервере. Мы проверяем, является ли значение в реквизите Логотип адресом временного хранилища. Если да, значит, пользователь загрузил новую картинку, и её нужно упаковать в ХранилищеЗначения.
&НаСервере
Процедура ПередЗаписьюНаСервере(Отказ, ТекущийОбъект, ПараметрыЗаписи)
// Проверяем, изменилась ли картинка (лежит ли в Логотипе адрес временного хранилища)
Если ЭтоАдресВременногоХранилища(Логотип) Тогда
// Получаем двоичные данные из хранилища
ДанныеКартинки = ПолучитьИзВременногоХранилища(Логотип);
// Записываем в реквизит объекта
ТекущийОбъект.Картинка = Новый ХранилищеЗначения(ДанныеКартинки);
// Не удаляйте адрес из временного хранилища вручную здесь,
// если планируете продолжать работу с формой,
// иначе картинка исчезнет из поля зрения пользователя сразу после записи.
КонецЕсли;
КонецПроцедуры
Посмотрим на пример того, как сделать так, чтобы картинка не «пропадала» при закрытии и повторном открытии карточки справочника. Для этого нам нужно преобразовать данные из типа ХранилищеЗначения обратно в навигационную ссылку, которую понимает Поле картинки. Это необходимо делать в нескольких местах: при создании формы, при чтении объекта и сразу после записи.
&НаСервере
Процедура ОбновитьОтображениеЛоготипа()
// Если объект уже записан в базе, получаем ссылку на его реквизит
Если Не Объект.Ссылка.Пустая() Тогда
Логотип = ПолучитьНавигационнуюСсылку(Объект.Ссылка, "Картинка");
КонецЕсли;
КонецПроцедуры
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
ОбновитьОтображениеЛоготипа();
КонецПроцедуры
&НаСервере
Процедура ПриЧтенииНаСервере(ТекущийОбъект)
ОбновитьОтображениеЛоготипа();
КонецПроцедуры
&НаСервере
Процедура ПриЗаписиНаСервере(Отказ, ТекущийОбъект, ПараметрыЗаписи)
// После записи обновляем ссылку, чтобы она указывала на актуальные данные в БД
ОбновитьОтображениеЛоготипа();
КонецПроцедуры
Рассмотрим подробнее ошибки, которые часто совершают разработчики. Например, попытка создать объект Новый Картинка(ПутьКФайлу) на клиенте. В управляемых формах 1С прямой доступ к файлам ограничен в целях безопасности. Поэтому правильный путь — использование временного хранилища через НачатьПомещениеФайла.
Также проанализируем ситуацию с реквизитом СсылкаНаКартинку. Если вы хотите отображать имя файла на форме, убедитесь, что вы обращаетесь к Объект.СсылкаНаКартинку, а не к элементам формы напрямую. Присваивание значения должно происходить именно реквизиту объекта, чтобы платформа знала, что данные нужно сохранить в таблицу базы данных.
Основные рекомендации:
УникальныйИдентификатор формы в метод НачатьПомещениеФайла. Это гарантирует очистку временных данных после закрытия окна.Пропорционально. Это предотвратит искажение логотипов с разным соотношением сторон.ПриЧтенииНаСервере. Это критично для корректной работы кнопок навигации «Следующий» / «Предыдущий» в форме элемента, так как ПриСозданииНаСервере в этих случаях не срабатывает повторно.Таким образом, мы построили надежный мост между файловой системой клиента, временным хранилищем сервера и постоянным хранилищем базы данных. Этот алгоритм является универсальным и может быть использован в любых конфигурациях для работы с изображениями и другими файлами.