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