При разработке интерфейсов на платформе 1С:Предприятие 8 программисты часто сталкиваются с неочевидным поведением платформы при работе с числовыми данными. Классический пример — необходимость ввода пользователем оценки или показателя в диапазоне от 0 до 3. При попытке ввести «0» поле ввода может очищаться, подчеркиваться красным цветом как незаполненное или выдавать ошибку проверки.
В этой статье мы подробно разберем, почему платформа 1С так реагирует на ввод нуля, и рассмотрим несколько профессиональных и надежных способов решения этой проблемы без сомнительного перевода полей в строковый тип.
Давайте проанализируем ситуацию. В системе 1С для типов данных Число по умолчанию не существует понятия "пустого значения" (такого как Неопределено или NULL в базах данных). Физически «пустым» значением для числа является именно 0.
Если для элемента формы (или реквизита объекта) включено свойство Проверка заполнения (или Автоотметка незаполненного), платформа использует стандартный алгоритм проверки:
0 интерпретируется как «не заполнено».Именно поэтому стандартная проверка заполнения не подходит для полей, где ноль — это значащая, допустимая величина.
Рассмотрим по шагам практические варианты решения этой задачи.
Если ноль является полноправным значением, нам необходимо отключить стандартную автоматическую проверку заполнения в свойствах реквизита. Вместо этого мы реализуем гибкую проверку на уровне модуля формы или модуля объекта.
Для отключения стандартной проверки выполним следующие действия:
Не проверять.Теперь напишем обработчик проверки заполнения в модуле объекта (например, документа или справочника), чтобы система не позволяла записать некорректные данные, но при этом пропускала ноль:
Процедура ОбработкаПроверкиЗаполнения(Отказ, ПроверяемыеРеквизиты)
// Исключаем реквизит из стандартной проверки, если он там остался
Позиция = ПроверяемыеРеквизиты.Найти("ВероятностьРиска");
Если Позиция <> Неопределено Тогда
ПроверяемыеРеквизиты.Удалить(Позиция);
КонецЕсли;
// Выполняем собственную корректную проверку диапазона
Если ВероятностьРиска < 0 Или ВероятностьРиска > 3 Тогда
ОбщегоНазначенияКлиентСервер.СообщитьПользователю(
"Поле 'Вероятность риска' должно быть заполнено числом в диапазоне от 0 до 3!",
,
"ВероятностьРиска",
,
Отказ
);
КонецЕсли;
КонецПроцедуры
Чтобы пользователь четко видел введенный ноль, а не пустую строку, необходимо правильно настроить свойства отображения элемента формы (поля ввода). Для этого используются свойства Формат и Формат редактирования.
Разберем детально настройку форматной строки:
ЧН). 0. Конструктор сформирует строку вида: ЧН=0. Это укажет платформе принудительно выводить цифру "0" на экран, даже если в реквизите хранится пустое числовое значение.ЧН=0. Это предотвратит исчезновение нуля в тот момент, когда пользователь активирует поле ввода клавиатурой.Также обратим внимание на важное свойство поля ввода — Выдавать ноль. Если установить этот флаг в значение Истина, то при очистке поля пользователем (например, нажатием клавиши Delete или Backspace) система автоматически подставит в него значение 0, не оставляя поле неопределенным.
Когда диапазон значений крайне мал (как в нашем примере от 0 до 3), идеальным решением является использование встроенных механизмов платформы для ограничения ввода. Это полностью избавит нас от необходимости писать код валидации «больше 3» или «меньше 0».
Настроим свойства числового поля ввода на форме:
0.3.Благодаря этим настройкам пользователь физически не сможет ввести в поле символы, не входящие в диапазон 0-3. При попытке прокрутить значение ниже нуля или выше тройки, платформа заблокирует изменение.
Если мы хотим полностью исключить ручной ввод с клавиатуры и защитить данные от ошибок, можно настроить поле ввода для работы со статическим списком выбора. Это очень эргономичное решение.
Посмотрим на пример программного заполнения списка выбора при создании формы:
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
// Находим элемент формы и включаем режим выбора из списка
ЭлементФормы = Элементы.ВероятностьРиска;
ЭлементФормы.РежимВыбораИзСписка = Истина;
// Очищаем и наполняем список выбора числовыми значениями
ЭлементФормы.СписокВыбора.Очистить();
ЭлементФормы.СписокВыбора.Добавить(0, "0");
ЭлементФормы.СписокВыбора.Добавить(1, "1");
ЭлементФормы.СписокВыбора.Добавить(2, "2");
ЭлементФормы.СписокВыбора.Добавить(3, "3");
КонецПроцедуры
При такой настройке поле ввода превратится в выпадающий список (Combo Box). Пользователь сможет выбрать только предопределенные значения: 0, 1, 2 или 3. Очистить поле до "пустоты" станет невозможно, а выбранный ноль будет гарантированно сохранен в базе данных.
В обсуждении на форуме упоминалась проблема: при изменении значений полей формула умножения переставала работать, если одно из полей содержало 0. Проанализируем исходный код обработчика события:
// Небезопасный код, который может приводить к ошибкам расчетов
ТекДанные.ЗначимостьРиска = ТекДанные.ВероятностьРиска * ТекДанные.ПоследствияРиска;
Если одно из полей очищается пользователем (или содержит неопределенное состояние из-за неверно настроенного формата), в формуле может произойти неявное приведение типов, либо событие ПриИзменении просто не сработает из-за того, что платформа посчитала действие пользователя «очисткой», а не установкой значения.
Чтобы гарантировать корректность математических операций, всегда используйте явное преобразование типов с помощью функции Число(). Это позволит безопасно преобразовывать любые пустые значения элементов формы в математический ноль.
Давайте напишем правильный и отказоустойчивый обработчик события изменения полей:
&НаКлиенте
Процедура ОценкаПриИзмененииПоказателей(Элемент)
ТекДанные = Элементы.Оценка.ТекущиеДанные;
Если ТекДанные = Неопределено Тогда
Возврат;
КонецЕсли;
// Гарантируем получение числового типа, даже если в поле визуально пусто
Вероятность = Число(ТекДанные.ВероятностьРиска);
Последствия = Число(ТекДанные.ПоследствияРиска);
// Выполняем расчет
ТекДанные.ЗначимостьРиска = Вероятность * Последствия;
КонецПроцедуры
Важный совет: назначьте эту единую процедуру в качестве обработчика события ПриИзменении сразу для двух элементов формы — и для поля ВероятностьРиска, и для поля ПоследствияРиска. В таком случае расчет значения ЗначимостьРиска будет выполняться мгновенно и интерактивно при редактировании любого из влияющих показателей.