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