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