Как получить значение ресурса регистра сведений по ключу и отобразить картинку по пути к файлу

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

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

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

Способ 1. Использование менеджера записи

Самый очевидный способ, который часто применяют начинающие разработчики, — это создание объекта МенеджерЗаписи. Этот объект позволяет «прочитать» конкретную запись из базы данных, передав ему значения ключевых полей. Выясним, как это реализовать в коде.

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


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

Важный нюанс: Метод ЗаполнитьЗначенияСвойств отлично работает, так как имена измерений в ключе записи совпадают с именами измерений в менеджере записи. Однако помните, что создание объекта МенеджерЗаписи — достаточно «тяжелая» операция для сервера, особенно если пользователь быстро пролистывает список.

Способ 2. Получение данных через менеджер регистра (Метод Получить)

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

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


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

Способ 3. Оптимизация через запрос в Динамическом списке

Проанализируем архитектурный подход. Вместо того чтобы каждый раз при активации строки «ходить» на сервер за путем к файлу, мы можем сразу включить этот путь в данные самого динамического списка. Это позволит избежать лишних серверных вызовов &НаСервереБезКонтекста.

Выполним следующие шаги для настройки:

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

Теперь в обработчике СписокПриАктивизацииСтроки данные будут доступны мгновенно через свойство Элементы.Список.ТекущиеДанные.ПутьКФайлу. Нам останется только передать уже известный путь на сервер для получения двоичных данных, минуя поиск в регистре. Для изучения различных подходов к расширению состава колонок можно использовать руководство по методам добавления полей в динамические списки.

Обеспечение отзывчивости интерфейса

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

Идея заключается в том, чтобы не бежать на сервер сразу, а подождать несколько мгновений (например, 0.2 секунды). Если пользователь продолжает листать список, мы сбрасываем ожидание. Если остановился — загружаем картинку.


&НаКлиенте
Процедура СписокПриАктивизацииСтроки(Элемент)
    // Отключаем предыдущий вызов, если он был запланирован
    ОтключитьОбработчикОжидания("Подключаемый_ЗагрузитьКартинку");
    // Запланируем новый вызов через 200 мс
    ПодключитьОбработчикОжидания("Подключаемый_ЗагрузитьКартинку", 0.2, Истина);
КонецПроцедуры

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

Работа в Веб-клиенте

Нужно учитывать, что если ваше приложение работает через браузер, прямой путь к файлу вида C:/myfolder/myfile.jpg со стороны клиента будет недоступен. Чтение файла в Новый ДвоичныеДанные() должно происходить строго на стороне сервера, так как именно сервер 1С имеет доступ к файловой системе (или сетевым ресурсам). Помещение файла во временное хранилище и получение навигационной ссылки — это единственный надежный способ передать визуальные данные в веб-браузер или тонкий клиент, у которого нет прав доступа к указанному каталогу.

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

← На главную