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