Как устроено перетаскивание в формах 1С и как его включить
Содержание
Перетаскивание в 1С работает на событиях управляемой формы: элемент-источник отдаёт данные в событии НачалоПеретаскивания, а элемент-приёмник ловит их в событиях ПроверкаПеретаскивания и Перетаскивание. Чтобы Drag-and-Drop заработал, эти обработчики нужно назначить вручную — без них мышь просто выделяет строки.
Типичная задача: пользователь хочет перетащить несколько позиций из списка номенклатуры прямо в табличную часть документа, а не добавлять их по одной. Разработчик открывает форму, видит таблицу — но перетаскивание не срабатывает. Причина почти всегда в ненастроенных событиях, и реже — в том, что приёмник не разрешил нужное действие.
Из чего собран механизм перетаскивания
Drag-and-Drop в 1С — это не одно событие, а цепочка из трёх. Они делятся на сторону источника (откуда тащим) и сторону приёмника (куда бросаем).
- 🚀
НачалоПеретаскивания— срабатывает на источнике в момент, когда пользователь зажал кнопку мыши и потащил выделенные данные. Здесь можно отменить операцию или подготовить то, что поедет в приёмник. - 🔍
ПроверкаПеретаскивания— срабатывает на приёмнике многократно, пока курсор движется над ним. Здесь решается, можно ли бросить данные в это место: курсор показывает «разрешено» или «запрещено». - 📥
Перетаскивание— срабатывает на приёмнике один раз, когда пользователь отпустил кнопку мыши. Это и есть момент, когда вы принимаете данные и что-то с ними делаете.
Данные между источником и приёмником едут в объекте ПараметрыПеретаскивания. Он приходит параметром во все три обработчика. Главное его свойство — Значение: именно там лежит то, что перетащили.
Второе важное свойство — Действие: копирование это или перемещение. В обработчике ПроверкаПеретаскивания можно запретить операцию, присвоив ПараметрыПеретаскивания.Действие = ДействиеПеретаскивания.Отмена — тогда курсор покажет запрет и бросить данные не получится.
Полный жизненный цикл одного перетаскивания выглядит так:
- Пользователь зажал мышь на выделении → срабатывает
НачалоПеретаскиванияу источника. Если здесь присвоить параметруВыполнятьзначениеЛожь, операция не начнётся. - Пользователь ведёт курсор → на приёмнике раз за разом срабатывает
ПроверкаПеретаскивания, и курсор меняет вид в зависимости от того, разрешён ли бросок. - Пользователь отпустил кнопку над приёмником → один раз срабатывает
Перетаскивание, и данные принимаются.
Полезный приём: в НачалоПеретаскивания вы можете сами переопределить ПараметрыПеретаскивания.Значение. Например, вместо ссылки передать структуру с дополнительными полями — артикул, остаток, цену. Тогда приёмнику не придётся снова ходить на сервер за этими данными: всё приедет вместе с перетаскиванием.
Что именно лежит в Значение по умолчанию, зависит от источника. Для динамического списка это, как правило, массив ссылок на выделенные элементы. Для таблицы формы — данные перетаскиваемой строки. Самый надёжный способ узнать точный состав — поставить точку останова в обработчике и посмотреть Значение в отладчике.
Как включить перетаскивание на элементе формы
Отдельной «галочки включить Drag-and-Drop» в палитре свойств нет. Механизм включается тем, что вы назначаете обработчики событий.
Порядок в конфигураторе:
- Откройте управляемую форму и выделите элемент, который станет источником (например, таблицу со списком товаров).
- В палитре свойств найдите раздел
Событияи создайте обработчикНачалоПеретаскивания. Даже пустой обработчик разрешает старт перетаскивания. - Выделите элемент-приёмник (например, таблицу документа).
- У приёмника создайте два обработчика:
ПроверкаПеретаскиванияиПеретаскивание.
Если источник и приёмник — один и тот же элемент (перетаскиваем строки внутри одной таблицы, чтобы поменять их порядок), все три обработчика назначаются на него же.
Частая ошибка новичка: назначить только событие Перетаскивание у приёмника и забыть ПроверкаПеретаскивания. Без проверки курсор будет показывать запрет, и до обработки отпускания дело не дойдёт.
В событиях-приёмниках есть ещё два параметра — Строка и Поле. Строка указывает, над какой строкой приёмника сейчас курсор, Поле — над какой колонкой. По ним удобно принимать данные не «в конец списка», а в конкретное место.
Перестановка строк внутри одной таблицы
Отдельный случай — не перенос из списка в список, а изменение порядка строк внутри одной таблицы (поднять строку выше или ниже перетаскиванием). Здесь источник и приёмник совпадают, а все три обработчика назначаются на один и тот же элемент.
Логика в событии Перетаскивание такая: Значение указывает на перетаскиваемую строку, Строка — на ту, над которой её отпустили. Вам нужно перенести первую к позиции второй. Так как у строк табличной части нет «порядкового номера» в привычном смысле, порядок задаётся физическим положением строки в коллекции — поэтому перестановку делают через встроенные операции перемещения строк коллекции, а не пересчётом индексов вручную.
Если же в табличной части есть собственная колонка-нумератор (например, НомерСтроки или Порядок), после перестановки её нужно перезаполнить — иначе визуальный порядок и значение в колонке разойдутся.
Где перетаскивание встречается в типовых конфигурациях
В типовых решениях 1С перетаскивание уже используется в нескольких стандартных местах, и логика там та же — три события формы.
- Подбор товаров. В формах подбора номенклатуры позиции можно перетаскивать из списка в табличную часть документа, а не только добавлять двойным кликом.
- Файлы и присоединённые документы. В подсистеме работы с файлами внешние файлы перетаскиваются из проводника Windows прямо в карточку объекта. В этом случае в
Значениеприходит набор переданных файлов. - Группировка в иерархических справочниках. Элемент справочника перетаскиванием переносится в другую группу — так меняется родитель.
- Настройка колонок и порядка строк. Внутри одной таблицы строки перетаскиванием меняют местами.
Отсюда простое правило: если вам нужно воспроизвести поведение «как в типовой», смотрите не на метаданные объекта, а на обработчики событий его формы. Перетаскивание — это всегда свойство формы и её элементов, а не справочника или документа.
Поэтому и переносить механизм из конфигурации в конфигурацию нельзя «копированием объекта». Нужная форма и её обработчики переносятся вместе с элементом формы. Если делаете это через расширение конфигурации , добавьте в заимствованную форму свои обработчики перетаскивания — исходные типовые обработчики при этом остаются на месте.
Пример: переносим позиции из списка в табличную часть
Разберём самый частый сценарий — пользователь выделяет несколько строк в списке номенклатуры и перетаскивает их в таблицу Товары документа.
На источнике (списке) достаточно пустого обработчика — он разрешает старт:
&НаКлиенте
Процедура СписокНоменклатурыНачалоПеретаскивания(Элемент, ПараметрыПеретаскивания, Выполнять)
// Данные уже в ПараметрыПеретаскивания.Значение.
// При необходимости можно прервать старт: Выполнять = Ложь;
КонецПроцедуры
На приёмнике (таблице Товары) в проверке снимаем стандартную обработку, чтобы платформа не пыталась обработать бросок по-своему:
&НаКлиенте
Процедура ТоварыПроверкаПеретаскивания(Элемент, ПараметрыПеретаскивания, СтандартнаяОбработка, Строка, Поле)
СтандартнаяОбработка = Ложь;
КонецПроцедуры
И принимаем данные в событии Перетаскивание. Значение может быть и одной ссылкой, и массивом ссылок — обрабатываем оба случая:
&НаКлиенте
Процедура ТоварыПеретаскивание(Элемент, ПараметрыПеретаскивания, СтандартнаяОбработка, Строка, Поле)
СтандартнаяОбработка = Ложь;
Значение = ПараметрыПеретаскивания.Значение;
Если ТипЗнч(Значение) = Тип("Массив") Тогда
Для Каждого Ссылка Из Значение Цикл
ДобавитьТоварВТаблицу(Ссылка);
КонецЦикла;
Иначе
ДобавитьТоварВТаблицу(Значение);
КонецЕсли;
КонецПроцедуры
&НаКлиенте
Процедура ДобавитьТоварВТаблицу(Номенклатура)
НоваяСтрока = Объект.Товары.Добавить();
НоваяСтрока.Номенклатура = Номенклатура;
НоваяСтрока.Количество = 1;
КонецПроцедуры
Не делайте запрос к серверу внутри цикла по строкам. Если при добавлении нужно подтянуть цену, единицу измерения или остаток, соберите все ссылки в массив и получите данные одним серверным вызовом, а потом разложите по строкам. Иначе перетаскивание двадцати позиций превратится в двадцать обращений к базе.
Сам обработчик Перетаскивание выполняется на клиенте, поэтому обращение к данным информационной базы из него напрямую недоступно — цену и остатки получают серверной процедурой. Это ещё одна причина делать один пакетный вызов вместо запроса на каждую строку.
Почему перетаскивание тормозит или не срабатывает
Жалоба «Drag-and-Drop не работает » почти всегда сводится к нескольким типовым причинам. Разберём их по симптомам.
НачалоПеретаскивания либо сам элемент не поддерживает старт перетаскивания. Проверьте раздел «События» в свойствах элемента-источника.ПроверкаПеретаскивания, либо в ней действие сброшено в ДействиеПеретаскивания.Отмена, либо не снята СтандартнаяОбработка. Разрешите бросок в проверке.Перетаскивание игнорируется параметр Строка. Используйте его, чтобы определить позицию вставки.Отдельно про скорость. Перетаскивание само по себе лёгкое — тормозит не оно, а то, что вы делаете в обработчике Перетаскивание. Правило простое: клиентский обработчик должен быстро принять данные и один раз сходить на сервер за всем сразу. Любой цикл с обращением к базе внутри — источник фризов.
Если перетаскиваются тысячи строк из динамического списка, помните, что в Значение приедет массив идентификаторов или ссылок на всё выделение. Обрабатывать его имеет смысл порциями, а не строить из него один гигантский запрос.
Копирование или перемещение — как различить
По умолчанию перетаскивание выполняется как перемещение, а при зажатой клавише Ctrl — как копирование. Какое действие выбрал пользователь, видно в свойстве ПараметрыПеретаскивания.Действие в момент броска.
Если ваш приёмник должен принимать данные только одним способом (скажем, всегда копировать, не трогая источник), не полагайтесь на клавишу: явно разрешите нужный вариант в ПроверкаПеретаскивания через свойство ДопустимыеДействия объекта параметров. Тогда пользователь не сможет случайно «переместить» данные и опустошить исходный список.
Разница важна, когда источник и приёмник — разные объекты. При перемещении логично ожидать, что строка из источника исчезнет; при копировании — останется. Приёмник сам отвечает за удаление строки из источника, платформа за него это не делает. Поэтому в сценарии «перенести, а не скопировать» удаление исходной строки пишут отдельно, обычно уже после успешной вставки в приёмник.
Перетаскивание в веб-клиенте и тонком клиенте
Один и тот же код обработчиков работает во всех клиентах, но поведение мыши отличается.
| Сценарий | Тонкий клиент | Веб-клиент |
|---|---|---|
| Перенос строк внутри формы | Работает | Работает |
| Перенос между элементами одной формы | Работает | Работает |
| Перетаскивание файлов из ОС в форму | Работает | Ограничено возможностями браузера |
| Сенсорный ввод (планшет, тач-экран) | Зависит от устройства | Поддержка ограничена |
Главное отличие — перетаскивание внешних файлов из проводника. В тонком клиенте это штатная операция. В веб-клиенте перенос файлов зависит от браузера и его настроек безопасности, поэтому критичный сценарий загрузки файлов лучше дублировать обычной кнопкой выбора файла — чтобы пользователь не остался без возможности прикрепить документ.
Если приложение открывают с планшетов, не делайте перетаскивание единственным способом выполнить действие. На сенсорном экране долгий тап и перетаскивание распознаются не всегда одинаково. Продублируйте операцию командой в панели или контекстным меню.
Логика событий при этом одинаковая. Если Drag-and-Drop работает в тонком клиенте и не работает в веб-клиенте, дело не в коде обработчиков, а в ограничениях самого веб-клиента на конкретную операцию — чаще всего на работу с файлами.
Частые вопросы
Чем отличаются события `ПроверкаПеретаскивания` и `Перетаскивание`?
ПроверкаПеретаскивания срабатывает многократно, пока курсор движется над приёмником, — она управляет видом курсора и тем, разрешён ли бросок. Перетаскивание срабатывает один раз, в момент отпускания кнопки мыши, — в нём вы фактически принимаете данные.Что лежит в `ПараметрыПеретаскивания.Значение`?
Как запретить бросок в конкретную строку или колонку?
ПроверкаПеретаскивания проверьте параметры Строка и Поле и, если место неподходящее, присвойте ПараметрыПеретаскивания.Действие = ДействиеПеретаскивания.Отмена. Курсор покажет запрет.Почему курсор при перетаскивании всегда показывает «запрещено»?
ПроверкаПеретаскивания, в нём снята СтандартнаяОбработка и действие не сброшено в отмену.