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