В процессе разработки часто возникает задача кастомизации интерфейса под конкретные нужды пользователя. Например, при формировании динамических колонок в документах или отчетах на основе данных из регистра сведений может потребоваться хранение настроек визуализации, таких как Цвет фона или Цвет текста. Однако стандартная платформа 1С накладывает определенные ограничения на работу с типом данных ХранилищеЗначения непосредственно на формах. Разберем подробно, как обойти эти ограничения и реализовать удобный механизм выбора и сохранения цвета.
Основная сложность заключается в том, что реквизит с типом ХранилищеЗначения нельзя просто вынести на управляемую форму. Кроме того, объект типа Цвет в 1С бывает трех видов: абсолютный (RGB), Web-цвет и цвет стиля. Если мы попытаемся хранить цвет просто как строку с RGB-компонентами, то при выборе цвета из системного стиля (например, "Цвет текста кнопки") платформа вернет значения "-1" для красного, зеленого и синего каналов. Это делает невозможным простое сохранение числовых показателей.
Рассмотрим несколько эффективных способов решения этой задачи, начиная от работы с временным хранилищем и заканчивая сериализацией объектов.
Это классический подход для работы с ХранилищемЗначения в управляемом приложении. Поскольку мы не можем напрямую связать элемент формы с ресурсом регистра, нам необходимо организовать "транспортировку" данных между сервером и клиентом. Разберем этот процесс по шагам.
ВыбранныйЦвет с типом Цвет.ПриЧтенииНаСервере извлечем данные из регистра.ПередЗаписьюНаСервере упакуем данные обратно.Проанализируем пример кода для реализации этой логики:
&НаСервере
Процедура ПриЧтенииНаСервере(ТекущийОбъект)
// Извлекаем цвет из ресурса "ДанныеЦвета" (тип ХранилищеЗначения)
Если ТипЗнч(ТекущийОбъект.ДанныеЦвета) = Тип("ХранилищеЗначения") Тогда
ЦветИзХранилища = ТекущийОбъект.ДанныеЦвета.Получить();
Если ТипЗнч(ЦветИзХранилища) = Тип("Цвет") Тогда
ЭтаФорма.ВыбранныйЦвет = ЦветИзХранилища;
КонецЕсли;
КонецЕсли;
КонецПроцедуры
&НаСервере
Процедура ПередЗаписьюНаСервере(Отказ, ТекущийОбъект, ПараметрыЗаписи)
// Помещаем объект Цвет в ХранилищеЗначения перед сохранением записи регистра
ТекущийОбъект.ДанныеЦвета = Новый ХранилищеЗначения(ЭтаФорма.ВыбранныйЦвет);
КонецПроцедуры
Этот метод хорош тем, что он сохраняет объект Цвет целиком, включая информацию о том, является ли он цветом стиля или абсолютным RGB-значением.
Если по каким-то причинам вы не хотите использовать ХранилищеЗначения в качестве типа ресурса (например, для облегчения веса базы или удобства выгрузки), можно использовать строковый реквизит большой длины. Чтобы не потерять свойства цвета, воспользуемся XDTO-сериализатором. Он позволяет превратить любой сложный объект 1С в структурированную XML-строку.
Рассмотрим, как реализовать функции преобразования:
// Преобразование цвета в строку XML
Функция ЦветВXML(ЗначениеЦвета) Экспорт
Возврат СериализаторXDTO.ЗаписатьXML(ЗначениеЦвета);
КонецФункции
// Восстановление цвета из строки XML
Функция XMLВЦвет(СтрокаXML) Экспорт
Чтение = Новый ЧтениеXML;
Чтение.УстановитьСтроку(СтрокаXML);
Возврат СериализаторXDTO.ПрочитатьXML(Чтение, Тип("Цвет"));
КонецФункции
Этот способ гарантирует, что даже специфические системные цвета будут восстановлены корректно. В ресурсе регистра в этом случае должен быть установлен тип Строка (длиной 250+ символов или неограниченная).
Наиболее простой в реализации, но менее "красивый" с точки зрения чистоты данных метод — использование системной функции ЗначениеВСтрокуВнутр(). Она переводит объект во внутренний формат 1С, который также содержит все необходимые метаданные о типе цвета.
Посмотрим на пример записи данных:
// При изменении цвета на форме
&НаКлиенте
Процедура ВыбранныйЦветПриИзменении(Элемент)
СтрокаДляЗаписи = ПолучитьВнутреннююСтрокуЦвета(ВыбранныйЦвет);
КонецПроцедуры
&НаСервереБезКонтекста
Функция ПолучитьВнутреннююСтрокуЦвета(ЗначениеЦвета)
Возврат ЗначениеВСтрокуВнутр(ЗначениеЦвета);
КонецФункции
Для восстановления объекта используется обратная функция ЗначениеИзСтрокиВнутр(). Этот метод стабильно работает в толстом и тонком клиентах, однако его не рекомендуется использовать для интеграции с внешними системами, так как формат строки является проприетарным для 1С.
Если стоит задача сделать интерфейс максимально наглядным, но при этом избежать проблем с типами данных, можно пойти по пути создания "конструктора цвета". Как предлагалось в обсуждении, мы можем создать три числовых поля (Красный, Зеленый, Синий) и одно поле Декорация для предпросмотра.
Выясним причину выбора этого метода: он обеспечивает стопроцентную прозрачность данных. Вы всегда видите конкретные цифры в регистре и можете легко использовать их в запросах или при формировании условного оформления.
Для визуализации выбора используем следующий код:
&НаКлиенте
Процедура ПодобратьЦвет(Команда)
Диалог = Новый ДиалогВыбораЦвета;
Диалог.Цвет = Новый Цвет(Элементы.ПолеR, Элементы.ПолеG, Элементы.ПолеB);
Если Диалог.Выбрать() Тогда
Элементы.ПолеR = Диалог.Цвет.Красный;
Элементы.ПолеG = Диалог.Цвет.Зеленый;
Элементы.ПолеB = Диалог.Цвет.Синий;
// Обновляем предпросмотр на форме
Элементы.ДекорацияЦвет.ЦветФона = Диалог.Цвет;
КонецЕсли;
КонецПроцедуры
Проанализировав ситуацию, можно сделать следующие выводы:
ПриИзменении.Важный момент: при использовании любого из методов не забывайте про производительность. Чтение из ХранилищаЗначения в цикле при выводе списка может замедлить работу. Если цветов много, лучше кэшировать их в переменные модуля или использовать условное оформление динамического списка, предварительно подготовив данные на сервере.