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