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