Разберем распространенную ситуацию, с которой сталкиваются разработчики и администраторы баз данных 1С: пользователи случайно, сами того не замечая, переносят группы (папки) внутри иерархического справочника с помощью мыши (механизм drag-and-drop). Это приводит к нарушению структуры данных и путанице. Рассмотрим подробнее, какими способами мы можем запретить перенос папок, сохранив при этом удобство работы с системой.
Проанализируем самый простой и быстрый способ решения задачи — отключение механизма перетаскивания на уровне элемента управления (таблицы формы), отображающего список справочника или дерево. В платформе 1С за возможность перемещения строк с помощью мыши отвечают два свойства элемента формы:
РазрешитьНачалоПеретаскивания (в английском синтаксисе EnableStartDrag) — разрешает или запрещает захватывать данные из этого списка для переноса.РазрешитьПеретаскивание (в английском синтаксисе EnableDrag) — разрешает или запрещает сбрасывать перетаскиваемые данные в этот список.Если мы установим оба этих свойства в значение Ложь, пользователи больше не смогут ничего перетаскивать внутри формы списка. Однако у этого метода есть существенный недостаток: он работает глобально для всего списка. Это означает, что если по бизнес-логике нам нужно запретить перемещение только групп, но разрешить перетаскивать обычные элементы из одной папки в другую, этот способ нам не подойдет. Посмотрим на альтернативные варианты.
Если нам необходимо запретить перенос исключительно групп, оставив возможность drag-and-drop для элементов, мы используем обработчики событий самой формы списка или дерева. Разберем по шагам, как это реализовать.
Нам понадобится событие ПроверкаПеретаскивания. Оно срабатывает в тот момент, когда пользователь захватил объект и наводит его на потенциальный приемник (другую папку). В этот момент система передает в обработчик специальный объект, в котором содержится массив перетаскиваемых ссылок.
Мы можем программно обойти этот массив, проверить, является ли хотя бы одна из ссылок группой (используя стандартное свойство ЭтоГруппа), и если да — отменить действие. При этом курсор мыши изменится на запрещающий знак, визуально показывая пользователю, что операция недоступна.
Посмотрим на пример реализации данного механизма:
&НаКлиенте
Процедура СписокПроверкаПеретаскивания(Элемент, ПараметрыПеретаскивания, СтандартнаяОбработка, Строка, Поле)
// Проверяем, что именно перетаскивается
Если ТипЗнч(ПараметрыПеретаскивания.Значение) = Тип("Массив") Тогда
Для Каждого ПеретаскиваемаяСсылка Из ПараметрыПеретаскивания.Значение Цикл
// Если перетаскивается группа, отменяем действие
Если ОбщегоНазначенияСервер.ЭтоГруппа(ПеретаскиваемаяСсылка) Тогда
ПараметрыПеретаскивания.Действие = ДействиеПеретаскивания.Отмена;
Прервать;
КонецЕсли;
КонецЦикла;
КонецЕсли;
КонецПроцедуры
Важное замечание: вызов свойства ЭтоГруппа напрямую на клиенте для ссылки невозможен, поэтому в примере выше используется серверный вызов (например, через общий модуль) или предварительное получение данных о строке. Если вы работаете с управляемой формой, оптимальнее получать данные текущей строки из данных самой формы, чтобы избежать лишних серверных вызовов в динамическом событии.
Выясним причину, по которой описанных выше клиентских запретов может быть недостаточно. Перенос методом Drag-and-Drop — это лишь визуальный способ изменения реквизита Родитель. Опытный пользователь может просто открыть карточку группы и изменить поле "Родитель" вручную. Кроме того, родитель может быть изменен программно при различных загрузках данных из Excel или других баз.
Для создания надежной и железобетонной защиты необходимо добавить проверку непосредственно в модуль самого справочника. Рассмотрим подробнее использование события ПередЗаписью.
В этом обработчике мы проверяем следующее условие: если текущий записываемый объект является группой, и это не создание новой папки (то есть объект уже существует в базе), мы сравниваем новое значение реквизита Родитель с тем значением, которое сейчас сохранено в базе данных. Если они отличаются, значит, происходит попытка перемещения. В этом случае мы устанавливаем параметр Отказ в значение Истина.
Посмотрим на пример серверного кода в модуле объекта справочника:
Процедура ПередЗаписью(Отказ)
// Проверяем, что объект является группой и он уже записан в базу
Если ЭтоГруппа И Не ЭтоНовый() Тогда
// Получаем старое значение родителя из базы данных
СтарыйРодитель = ОбщегоНазначения.ЗначениеРеквизитаОбъекта(Ссылка, "Родитель");
// Сравниваем новое значение с тем, что в базе
Если Родитель <> СтарыйРодитель Тогда
Отказ = Истина;
Сообщение = Новый СообщениеПользователю;
Сообщение.Текст = "Перемещение групп (папок) в данном справочнике строго запрещено!";
Сообщение.Поле = "Родитель";
Сообщение.Сообщить();
КонецЕсли;
КонецЕсли;
КонецПроцедуры
Чтобы избежать путаницы и не заставлять пользователей получать ошибку при попытке записи, рекомендуется сделать реквизит Родитель в самой форме группы недоступным для редактирования. Установите для этого элемента управления на форме свойство ТолькоПросмотр или Доступность в значение Ложь. Таким образом, пользователи даже не смогут попытаться выбрать другую папку внутри карточки группы.
Если вы работаете в сложных корпоративных системах (например, ERP или Комплексная автоматизация), запрет на перемещение групп часто настраивается вообще без программирования — на уровне прав доступа. Через профили групп доступа или механизм RLS (Record Level Security) пользователям просто снимают права на изменение поля Родитель для записей, у которых установлен признак группы. Это автоматически делает невозможным как перетаскивание, так и ручное изменение, и система сама сформирует корректный интерфейс, заблокировав нужные поля.
Используя комплексный подход (ограничение Drag-and-Drop на форме + строгая проверка ПередЗаписью в модуле объекта), мы гарантируем, что иерархия наших групп останется в полной безопасности и не будет нарушена случайными действиями пользователей.