При работе с динамическими списками в управляемых формах «1С:Предприятие 8.3» часто возникает необходимость разрешить пользователям интерактивно переносить элементы и группы с помощью мыши (механизм Drag&Drop). Однако из-за случайных движений мыши пользователи могут ошибочно изменить родителя у справочника или группы. В этой статье разберем, как правильно перехватить завершение перетаскивания, спросить у пользователя подтверждение или отменить действие при выполнении определенных условий.
Частая ошибка разработчиков заключается в попытке отменить интерактивный перенос в событии ОкончаниеПеретаскивания. К моменту вызова этого события системная обработка источника уже завершена, и установка параметра СтандартнаяОбработка = Ложь не приведет к отмене изменения данных в базе.
Для правильной обработки отмены необходимо ориентироваться на следующую цепочку событий таблицы формы:
НачалоПеретаскивания — вызывается в источнике при старте захвата объекта мышью.ПроверкаПеретаскивания — срабатывает постоянно при перемещении курсора над таблицей-приемником. Позволяет визуально запретить сброс (показывает знак «запрещено»).Перетаскивание — возникает в приемнике в момент отпускания кнопки мыши. Это именно та точка, где нужно отменять стандартную обработку и запрашивать подтверждение.ОкончаниеПеретаскивания — вызывается в источнике после того, как перенос физически завершен.Разберем подробнее, как реализовать диалог подтверждения с помощью события Перетаскивание.
Так как в управляемом приложении 1С 8.3 диалоги вызываются асинхронно, мы не можем приостановить выполнение кода внутри события и ждать нажатия кнопки пользователем. Если разрешить стандартную обработку, платформа автоматически обновит родителя элемента в базе данных до того, как сработает асинхронный ответ.
Поэтому применяют следующий подход: в событии Перетаскивание всегда отменяют стандартную обработку, а сам перенос выполняют программно после получения положительного ответа от пользователя.
Перехват события на клиенте: В событии таблицы формы Перетаскивание устанавливаем СтандартнаяОбработка = Ложь. Это блокирует автоматическое изменение родителя платформой. Считываем перетаскиваемые данные из ПараметрыПеретаскивания.Значение и целевую строку Строка.
Вызов асинхронного диалога: Формируем процедуру-обработчик оповещения и вызываем ПоказатьВопрос.
Запись изменений на сервере: Если пользователь выбирает ответ «Да», передаем данные в серверную процедуру, меняем реквизит Родитель у перетаскиваемого объекта, записываем его и обновляем динамический список методами Обновить() или Прочитать().
Рассмотрим пример реализации на языке 1С:
&НаКлиенте
Процедура СписокПеретаскивание(Элемент, ПараметрыПеретаскивания, СтандартнаяОбработка, Строка, Поле)
// Отменяем автоматический перенос платформой
СтандартнаяОбработка = Ложь;
// Получаем перетаскиваемый элемент и целевую группу/элемент
ЭлементДляПереноса = ПараметрыПеретаскивания.Значение;
НовыйРодитель = Строка; // Ссылка на целевую строку таблицы
// Проверяем корректность данных
Если ЭлементДляПереноса = Неопределено Или НовыйРодитель = Неопределено Тогда
Возврат;
КонецЕсли;
// Формируем структуру параметров для передачи в обработчик оповещения
ДопПараметры = Новый Структура;
ДопПараметры.Вставить("ЭлементДляПереноса", ЭлементДляПереноса);
ДопПараметры.Вставить("НовыйРодитель", НовыйРодитель);
ОписаниеОповещения = Новый ОписаниеОповещения("ПослеОтветаНаВопросОПереносе", ЭтотОбъект, ДопПараметры);
ПоказатьВопрос(ОписаниеОповещения, "Вы уверены, что хотите переместить выбранный элемент?", РежимДиалогаВопрос.ДаНет);
КонецПроцедуры
&НаКлиенте
Процедура ПослеОтветаНаВопросОПереносе(Результат, ДополнительныеПараметры) Экспорт
Если Результат = КодВозвратаДиалога.Да Тогда
// Вызываем серверную процедуру изменения родителя
ПереместитьЭлементНаСервере(ДополнительныеПараметры.ЭлементДляПереноса, ДополнительныеПараметры.НовыйРодитель);
// Обновляем динамический список на форме
Элементы.Список.Обновить();
КонецЕсли;
КонецПроцедуры
&НаСервере
Процедура ПереместитьЭлементНаСервере(СсылкаНаОбъект, СсылкаНаНовогоРодителя)
ОбъектСправочника = СсылкаНаОбъект.ПолучитьОбъект();
ОбъектСправочника.Родитель = СсылкаНаНовогоРодителя;
Попытка
ОбъектСправочника.Записать();
Исключение
ВызватьИсключение НСтр("ru = 'Не удалось переместить элемент: '") + ОписаниеОшибки();
КонецПопытки;
КонецПроцедуры
Чтобы пользователь не мог даже отпустить мышь над некорректным родителем (например, попытка перенести папку саму в себя или в подчиненный элемент), проанализируем событие ПроверкаПеретаскивания.
В этом событии мы можем заранее сменить состояние курсора на «запрещено», установив действие перетаскивания:
&НаКлиенте
Процедура СписокПроверкаПеретаскивания(Элемент, ПараметрыПеретаскивания, СтандартнаяОбработка, Строка, Поле)
// Если перенос выполняется в пустую область или целевая строка недопустима
Если Строка = Неопределено Тогда
ПараметрыПеретаскивания.Действие = ДействиеПеретаскивания.Отмена;
КонецЕсли;
КонецПроцедуры
Если пользователи часто совершают ошибочные действия мышью, рассмотрим еще два практических варианта решения проблемы:
РазрешитьПеретаскивание. В событии формы при изменении этого флажка меняются свойства таблицы РазрешитьПеретаскивание и РазрешитьНачалоПеретаскивания. После завершения операции флажок автоматически снимается.