Как сделать поле доступным для новой строки, если оно заблокировано условным оформлением?

Программист 1С v8.3 (Управляемые формы)
← На главную

В разработке на платформе 1С часто возникает задача динамического управления интерфейсом. Одна из таких задач — управление доступностью полей в табличной части документа, особенно когда в дело вступает условное оформление. Рассмотрим типичную ситуацию: в документе есть табличная часть, где строки должны заполняться последовательно. Условное оформление блокирует поле в строке, если оно не заполнено, чтобы пользователь не мог редактировать "будущие" строки. Но как быть с самой первой незаполненной строкой, которую как раз и нужно сейчас заполнить? А если логика еще сложнее, и доступность текущей строки зависит от значения в предыдущей?

Проанализируем эту проблему по шагам и найдем наиболее правильное и масштабируемое решение, избежав распространенных ошибок.

Проблема: Конфликт логики и условного оформления

Сформулируем исходную задачу. Есть табличная часть документа, например, `Втулки`. В ней есть колонка `Состояние` с типом `Перечисление`. В настройках условного оформления формы задано правило:

Это правило отлично работает для уже заполненных документов, не давая редактировать пустые ячейки в середине списка. Но при добавлении новой строки пользователь сталкивается с тем, что поле `Состояние` в этой новой, еще пустой строке, оказывается сразу заблокированным. Задача — сделать это поле доступным именно в тот момент, когда пользователь должен его заполнить (например, в новой строке или в первой строке, следующей за полностью заполненной).

Ошибочный подход: Программное добавление нового правила оформления

Первая мысль, которая часто приходит в голову, — это "перебить" одно условное оформление другим. То есть, в момент добавления новой строки программно создать еще один элемент условного оформления, который установит `Доступность` в `Истина`.

Пример такого кода, который пытался применить автор вопроса:


&НаСервере
Процедура ОткрытьДоступностьПоляСостояние()
    Элемент = УсловноеОформление.Элементы.Добавить();
    
    // Указываем поле, к которому применяется оформление
    ПолеЭлемента = Элемент.Поля.Элементы.Добавить();
    ПолеЭлемента.Поле = Новый ПолеКомпоновкиДанных(Элементы.Втулки.Имя + "Состояние");
    
    // Устанавливаем свойство доступности
    Элемент.Оформление.УстановитьЗначениеПараметра("Доступность", Истина);
КонецПроцедуры

Этот код вызывается в событии, связанном с добавлением строки. Однако такой подход имеет серьезные недостатки:

Как показала практика автора, этот метод привел к тому, что после добавления нескольких строк и навигации по ним, ранее доступные поля снова блокировались, а логика становилась непредсказуемой.

Правильный подход: Управление доступностью через реквизит-флаг

Наиболее надежный и гибкий способ решения этой задачи — не "бороться" с условным оформлением, а "сотрудничать" с ним. Идея заключается в том, чтобы отделить логику определения доступности от самого оформления. Мы вводим дополнительный признак (флаг) для каждой строки, который будет явно указывать, должно ли поле быть доступным, а условное оформление будет просто реагировать на этот флаг.

Разберем реализацию этого метода по шагам.

Шаг 1: Добавление реквизита-флага в табличную часть

В конфигураторе откроем объект документа и в его табличную часть (`Втулки`) добавим новый реквизит. Назовем его, например, `СостояниеДоступно` и установим ему тип `Булево`. Этот реквизит не нужно выводить на форму, он будет служебным.

Шаг 2: Настройка условного оформления

Теперь вернемся в форму документа и изменим наше единственное правило условного оформления. Оно должно стать предельно простым:

Все! Теперь условное оформление не анализирует заполнено поле или нет. Оно просто смотрит на значение нашего флага. Вся сложная логика будет сосредоточена в коде формы, который управляет этим флагом.

Шаг 3: Программное управление флагом

Теперь нам нужно написать код, который будет в правильные моменты времени выставлять флаг `СостояниеДоступно` в `Истина` или `Ложь` для каждой строки табличной части. Для этого создадим на сервере отдельную процедуру, которая будет инкапсулировать всю логику проверки.

Логика, описанная в теме, такова: поле `Состояние` доступно в первой строке, а в последующих — только если в предыдущей строке `Состояние` имеет значение `Выполнено`.


&НаСервере
Процедура ОбновитьДоступностьПоляСостояние()
    
    // Если строк нет, делать нечего
    Если Объект.Втулки.Количество() = 0 Тогда
        Возврат;
    КонецЕсли;
    
    // Первая строка всегда доступна для редактирования (по условию задачи)
    Объект.Втулки[0].СостояниеДоступно = Истина;
    
    // Перебираем остальные строки, начиная со второй
    Для i = 1 По Объект.Втулки.Количество() - 1 Цикл
        
        // Получаем текущую и предыдущую строки
        ТекущаяСтрока = Объект.Втулки[i];
        ПредыдущаяСтрока = Объект.Втулки[i-1];
        
        // Проверяем условие: предыдущая строка должна быть в состоянии "Выполнено"
        Если ПредыдущаяСтрока.Состояние = ПредопределенноеЗначение("Перечисление.ХХХ_СостояниеВтулокВПроизводстве.Выполнено") Тогда
            ТекущаяСтрока.СостояниеДоступно = Истина;
        Иначе
            ТекущаяСтрока.СостояниеДоступно = Ложь;
        КонецЕсли;
        
    КонецЦикла;
    
КонецПроцедуры

Важный момент: Мы написали процедуру, но теперь нужно определить, когда ее вызывать. Ее нужно вызывать во всех случаях, когда состояние доступности может измениться.

1. При открытии формы:

Чтобы при открытии существующего документа доступность была рассчитана корректно.


&НаСервере
Процедура ПриЧтенииНаСервере(ТекущийОбъект)
    ОбновитьДоступностьПоляСостояние();
КонецПроцедуры

2. При создании формы:

Чтобы при создании нового документа логика тоже отработала (например, для первой строки).


&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
    ОбновитьДоступностьПоляСостояние();
КонецПроцедуры

3. При изменении значения в поле `Состояние`:

Это ключевой момент. Когда пользователь меняет статус в одной строке, это должно влиять на доступность следующей. Для этого используем событие `ПриИзменении` у поля `Состояние` в таблице формы.


&НаКлиенте
Процедура ВтулкиСостояниеПриИзменении(Элемент)
    ОбновитьДоступностьПоляСостояниеНаСервере();
КонецПроцедуры

&НаСервере
Процедура ОбновитьДоступностьПоляСостояниеНаСервере()
    ОбновитьДоступностьПоляСостояние();
КонецПроцедуры

4. При добавлении и удалении строк:

Аналогично, изменение состава строк требует пересчета доступности.


&НаКлиенте
Процедура ВтулкиПослеУдаления(Элемент)
    ОбновитьДоступностьПоляСостояниеНаСервере();
КонецПроцедуры

// Для добавления строки можно использовать событие ПриОкончанииРедактирования,
// так как новая строка становится частью коллекции после завершения ввода.
// Либо событие ПередНачаломДобавления, чтобы подготовить флаг.
// Более надежный вариант — пересчитывать после любого изменения данных.

Заключение

Рассмотренный подход с использованием реквизита-флага является предпочтительным для решения сложных задач по управлению интерфейсом. Его преимущества:

Таким образом, вместо того чтобы пытаться переопределить одно правило оформления другим, лучше создать для оформления явный и понятный источник данных (наш флаг) и управлять этим источником программно.

← На главную