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