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