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