Как реализовать перетаскивание (Drag-and-Drop) между двумя динамическими списками в 1С?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

В разработке интерфейсов на управляемых формах 1С часто возникает задача упростить взаимодействие пользователя с данными. Один из эффективных способов — реализовать механизм перетаскивания элементов (Drag-and-Drop) между различными элементами формы, например, между двумя динамическими списками. Это позволяет пользователям интуитивно понятно перемещать или копировать данные, что значительно повышает удобство работы. Рассмотрим подробно, как настроить такую функциональность с помощью встроенных событий платформы 1С.

Проанализируем по шагам, как настроить обработчики событий для источника и приемника данных, чтобы реализовать полноценное перемещение записей мышью.

Общий принцип работы механизма Drag-and-Drop

Механизм перетаскивания в 1С построен на обработке последовательности из четырех ключевых событий, которые возникают у элементов формы (в нашем случае, у таблиц динамических списков). Чтобы все работало корректно, нам нужно будет написать код для обработчиков как минимум двух из них.

Основные события:

  1. НачалоПеретаскивания — срабатывает у элемента-источника в тот момент, когда пользователь "схватил" элемент мышью и начал его тащить. Здесь мы определяем, что именно мы перетаскиваем и какое действие совершаем (копирование, перемещение).
  2. ПроверкаПеретаскивания — срабатывает у элемента-приемника, когда курсор с перетаскиваемым объектом входит в его пределы. В этом событии мы можем проверить, можно ли "бросить" данные сюда, и визуально оповестить пользователя, изменив вид курсора.
  3. Перетаскивание — ключевое событие, которое срабатывает у элемента-приемника в момент, когда пользователь "отпускает" кнопку мыши. Здесь происходит основная логика: получение переданных данных и их обработка (например, создание нового элемента в списке-приемнике).
  4. ОкончаниеПеретаскивания — срабатывает у элемента-источника после того, как "бросок" был совершен (или отменен). Здесь можно выполнить завершающие действия, например, удалить исходный элемент, если это было перемещение.

Для нашей задачи по перемещению данных из списка Список1 в Список2 нам понадобятся в первую очередь события НачалоПеретаскивания для источника и Перетаскивание для приемника.

Шаг 1: Инициация перетаскивания (событие НачалоПеретаскивания)

Первым делом нам нужно обработать момент, когда пользователь начинает перетаскивать строку из первого списка. Для этого создадим обработчик события НачалоПеретаскивания для таблицы формы, которая отображает Список1.

В этом обработчике нам нужно выполнить три действия:

  1. Указать, какое действие мы совершаем. Например, ДействиеПеретаскивания.Перемещение.
  2. Поместить в специальный параметр данные, которые мы хотим передать. Обычно это ссылка на перетаскиваемый объект.
  3. Отключить стандартную обработку события, чтобы платформа использовала нашу логику.

Посмотрим на пример кода:

Предположим, у нас есть форма с двумя динамическими списками: Список1 (источник) и Список2 (приемник). Для элемента формы, связанного со Списком1, создаем обработчик:


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

После выполнения этого кода платформа "знает", что мы начали перетаскивать объект, и готова передать ТекущиеДанныеИсточника.Ссылка в элемент-приемник.

Шаг 2: Обработка "броска" (событие Перетаскивание)

Теперь настроим логику для списка-приемника. Когда пользователь перетащит курсор на Список2 и отпустит кнопку мыши, сработает событие Перетаскивание. В нем мы получим данные, которые "положили" на первом шаге, и выполним нужные действия.

Задача обработчика Перетаскивание — принять данные и, например, создать на их основе новую запись в табличной части или новый элемент справочника, который отображается в Списке2.

Рассмотрим пример кода для Списка2:

В этом примере мы принимаем ссылку на номенклатуру из первого списка и добавляем ее в табличную часть "Товары" документа, который отображается во втором списке.


&НаКлиенте
Процедура Список2Перетаскивание(Элемент, Параметры, СтандартнаяОбработка, Строка, Поле)
    
    // Получаем данные, которые мы передали в событии НачалоПеретаскивания
    ПеретаскиваемаяСсылка = Параметры.Значение;
    
    // Проверяем, что нам передали именно ссылку на номенклатуру
    // (хорошая практика для избежания ошибок)
    Если ТипЗнч(ПеретаскиваемаяСсылка) = Тип("СправочникСсылка.Номенклатура") Тогда
        
        // Создаем новую строку в табличной части "Товары" на сервере
        ДобавитьСтрокуНаСервере(ПеретаскиваемаяСсылка);
        
        // Обновляем список, чтобы увидеть изменения
        Элементы.Список2.Обновить();
        
    КонецЕсли;
    
    // Отключаем стандартную обработку
    СтандартнаяОбработка = Ложь;
    
КонецПроцедуры

&НаСервере
Процедура ДобавитьСтрокуНаСервере(СсылкаНоменклатуры)
    
    // Получаем объект документа из реквизита формы
    ОбъектДокумента = РеквизитФормыВЗначение("Объект");
    
    // Добавляем новую строку
    НоваяСтрока = ОбъектДокумента.Товары.Добавить();
    НоваяСтрока.Номенклатура = СсылкаНоменклатуры;
    // Можно заполнить и другие реквизиты, например, количество по умолчанию
    НоваяСтрока.Количество = 1; 
    
    // Записываем изменения обратно в реквизит формы
    ЗначениеВРеквизитФормы(ОбъектДокумента, "Объект");
    
КонецПроцедуры

Таким образом, мы замкнули цикл: "взяли" данные в одном списке и "положили" их в другой, где на их основе была создана новая запись.

Дополнительно: Как определить строку, на которую бросили элемент?

Часто возникает более сложная задача: нужно не просто добавить элемент в конец списка, а выполнить действие относительно конкретной строки, на которую был "брошен" объект. Например, установить иерархическую связь или вставить новую строку перед целевой.

Для этого в обработчике Перетаскивание можно использовать свойство Элемент.ТекущиеДанные. Оно будет содержать данные той строки списка-приемника, над которой в данный момент находится курсор.

Пример получения данных целевой строки:


&НаКлиенте
Процедура Список2Перетаскивание(Элемент, Параметры, СтандартнаяОбработка, Строка, Поле)
    
    // Данные перетаскиваемого элемента
    ПеретаскиваемыеДанные = Параметры.Значение;
    
    // Данные строки, НА которую бросили
    ЦелевыеДанные = Элемент.ТекущиеДанные;
    
    Если ЦелевыеДанные <> Неопределено Тогда
        // Здесь мы можем использовать ЦелевыеДанные.Ссылка для своих целей
        Сообщить("Элемент '" + ПеретаскиваемыеДанные + "' был перетащен на элемент '" + ЦелевыеДанные.Ссылка + "'");
        // Например, можно сделать перетаскиваемый элемент дочерним для целевого
    Иначе
        // Если бросили не на строку, а на пустое место в таблице
        Сообщить("Элемент '" + ПеретаскиваемыеДанные + "' был добавлен в конец списка");
    КонецЕсли;

    // ... дальнейшая логика добавления ...

    СтандартнаяОбработка = Ложь;

КонецПроцедуры

Использование Элемент.ТекущиеДанные открывает широкие возможности для создания сложных и интуитивно понятных пользовательских интерфейсов, таких как настройка иерархии, сортировка перетаскиванием и многое другое.

← На главную