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