Работа с объектом ФорматированныйДокумент часто преподносит сюрпризы разработчикам, особенно когда дело касается длительного хранения данных в базе. Одной из наиболее неприятных ситуаций является ошибка «can't read file» или появление пустого окна вместо ожидаемого текста с картинками. Проанализируем, почему это происходит, и разберем по шагам, как обеспечить стабильную работу этого механизма.
Рассмотрим стандартную ситуацию: в конфигурации реализован регистр сведений, где один из реквизитов имеет тип ХранилищеЗначения. В этот реквизит мы записываем содержимое ФорматированныйДокумент. При первом открытии формы в рамках сеанса данные отображаются корректно, но при повторном обращении (особенно через обработчик ожидания или при обновлении данных) платформа выдает ошибку «can't read file».
Выясним причину такого поведения. Внутри платформы 1С ФорматированныйДокумент не является просто строкой. Для его отображения на форме платформа генерирует временный HTML-файл, который затем загружается во встроенный компонент браузера (в современных версиях это WebKit). Когда мы помещаем объект в ХранилищеЗначения, происходит его сериализация.
Критический момент: При повторном извлечении объекта из хранилища платформа может пытаться использовать ссылки на временные файлы, которые были созданы в предыдущем цикле обращения к объекту. Если операционная система или сама платформа уже очистили папку временных файлов, а объект в памяти продолжает ссылаться на старый путь — возникает ошибка доступа к файлу.
Проанализируем самый простой способ «лечения» данной проблемы. Зачастую разработчики просто присваивают полученное из хранилища значение реквизиту формы. Однако для стабильной работы ФорматированныйДокумент на форме лучше предварительно «сбросить» его состояние.
Посмотрим на пример правильного кода при получении данных на сервере:
&НаСервере
Процедура ПрочитатьОписаниеИзХранилища()
// Сначала получаем данные из регистра или справочника
Выборка = РегистрыСведений.МоиНапоминания.СоздатьМенеджерЗаписи();
Выборка.Ключ = Новый Структура("Идентификатор", ТекущийИД);
Выборка.Прочитать();
Если Выборка.Выбран() Тогда
// ВАЖНО: Инициализируем реквизит формы новым объектом
Объект.ОписаниеФД = Новый ФорматированныйДокумент();
// Только после этого извлекаем данные из хранилища
ДанныеИзХранилища = Выборка.ОписаниеХранилище.Получить();
Если ТипЗнч(ДанныеИзХранилища) = Тип("ФорматированныйДокумент") Тогда
Объект.ОписаниеФД = ДанныеИзХранилища;
КонецЕсли;
КонецЕсли;
КонецПроцедуры
Такой подход заставляет движок рендеринга пересоздать внутренние структуры отображения, что часто помогает избежать использования битых ссылок из кэша.
Опытные разработчики 1С рекомендуют не хранить сам объект ФорматированныйДокумент напрямую в ХранилищеЗначения. Это связано с тем, что формат сериализации этого объекта может меняться от версии к версии платформы, а внутренние ссылки на ресурсы (картинки) вида v8res:// крайне нестабильны.
Разберем более надежный алгоритм работы:
ХранилищеЗначения структуру, содержащую эти два элемента.УстановитьHTML().Рассмотрим пример реализации записи:
&НаСервере
Процедура СохранитьДокументНадежно(ТекущийОбъект)
ТекстHTML = "";
СтруктураКартинок = Новый Структура;
// Извлекаем данные из объекта ФорматированныйДокумент
ОписаниеФД.ПолучитьHTML(ТекстHTML, СтруктураКартинок);
// Формируем контейнер для хранения
КонтейнерДанных = Новый Структура;
КонтейнерДанных.Вставить("HTML", ТекстHTML);
КонтейнерДанных.Вставить("Ресурсы", СтруктураКартинок);
ТекущийОбъект.ОписаниеХранилище = Новый ХранилищеЗначения(КонтейнерДанных);
КонецПроцедуры
И пример восстановления данных при чтении:
&НаСервере
Процедура ВосстановитьДокументНадежно(ДанныеХранилища)
Контейнер = ДанныеХранилища.Получить();
Если ТипЗнч(Контейнер) = Тип("Структура") Тогда
// Создаем чистый объект
НовыйДокумент = Новый ФорматированныйДокумент();
// Принудительно устанавливаем HTML и картинки
// Это гарантирует, что WebKit отрисует все с нуля
НовыйДокумент.УстановитьHTML(Контейнер.HTML, Контейнер.Ресурсы);
Объект.ОписаниеФД = НовыйДокумент;
КонецЕсли;
КонецПроцедуры
Этот метод считается эталонным, так как он полностью обходит механизмы кэширования самой платформы и полагается только на чистые данные HTML.
Если вы используете ПодключитьОбработчикОжидания для автоматического обновления форматированного документа (например, раз в 30 секунд), вы можете столкнуться с тем, что окно становится пустым. Это происходит из-за оптимизации движка отрисовки: если элемент управления не в фокусе или форма не активна, WebKit может остановить рендеринг.
Чтобы этого избежать, после программного обновления данных рекомендуется вызвать метод формы ОбновитьОтображениеДанных(). В некоторых случаях помогает кратковременное изменение видимости элемента или его размеров, что заставляет графическую подсистему «проснуться».
Если ваш реквизит ХранилищеЗначения добавлен через расширение конфигурации, проанализируем еще один нюанс. Иногда при десериализации объектов из расширений платформа теряет типы внутренних коллекций. Если ошибка «can't read file» сохраняется, попробуйте временно перенести реквизит в основную конфигурацию для проверки.
Также не забывайте о возможности очистки локального кэша 1С. Ошибка может быть вызвана повреждением локальных файлов в каталоге %AppData%\Local\1C\1cv8\. Если после удаления этих папок проблема исчезает (пусть и временно) — значит, корень зла именно в механизме работы платформы с временными файлами отображения HTML.
Подведем итог: Для стабильной работы всегда используйте метод сохранения пары HTML + Картинки вместо сохранения объекта целиком. Это избавит вас от большинства проблем с отображением в управляемых формах.