Как устроено перетаскивание в формах 1С и как его включить

· 9 мин

Содержание

Перетаскивание в 1С работает на событиях управляемой формы: элемент-источник отдаёт данные в событии НачалоПеретаскивания, а элемент-приёмник ловит их в событиях ПроверкаПеретаскивания и Перетаскивание. Чтобы Drag-and-Drop заработал, эти обработчики нужно назначить вручную — без них мышь просто выделяет строки.

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

Из чего собран механизм перетаскивания

Drag-and-Drop в 1С — это не одно событие, а цепочка из трёх. Они делятся на сторону источника (откуда тащим) и сторону приёмника (куда бросаем).

  • 🚀 НачалоПеретаскивания — срабатывает на источнике в момент, когда пользователь зажал кнопку мыши и потащил выделенные данные. Здесь можно отменить операцию или подготовить то, что поедет в приёмник.
  • 🔍 ПроверкаПеретаскивания — срабатывает на приёмнике многократно, пока курсор движется над ним. Здесь решается, можно ли бросить данные в это место: курсор показывает «разрешено» или «запрещено».
  • 📥 Перетаскивание — срабатывает на приёмнике один раз, когда пользователь отпустил кнопку мыши. Это и есть момент, когда вы принимаете данные и что-то с ними делаете.

Данные между источником и приёмником едут в объекте ПараметрыПеретаскивания. Он приходит параметром во все три обработчика. Главное его свойство — Значение: именно там лежит то, что перетащили.

Второе важное свойство — Действие: копирование это или перемещение. В обработчике ПроверкаПеретаскивания можно запретить операцию, присвоив ПараметрыПеретаскивания.Действие = ДействиеПеретаскивания.Отмена — тогда курсор покажет запрет и бросить данные не получится.

Полный жизненный цикл одного перетаскивания выглядит так:

  1. Пользователь зажал мышь на выделении → срабатывает НачалоПеретаскивания у источника. Если здесь присвоить параметру Выполнять значение Ложь, операция не начнётся.
  2. Пользователь ведёт курсор → на приёмнике раз за разом срабатывает ПроверкаПеретаскивания, и курсор меняет вид в зависимости от того, разрешён ли бросок.
  3. Пользователь отпустил кнопку над приёмником → один раз срабатывает Перетаскивание, и данные принимаются.

Полезный приём: в НачалоПеретаскивания вы можете сами переопределить ПараметрыПеретаскивания.Значение. Например, вместо ссылки передать структуру с дополнительными полями — артикул, остаток, цену. Тогда приёмнику не придётся снова ходить на сервер за этими данными: всё приедет вместе с перетаскиванием.

Что именно лежит в Значение по умолчанию, зависит от источника. Для динамического списка это, как правило, массив ссылок на выделенные элементы. Для таблицы формы — данные перетаскиваемой строки. Самый надёжный способ узнать точный состав — поставить точку останова в обработчике и посмотреть Значение в отладчике.

Как включить перетаскивание на элементе формы

Отдельной «галочки включить Drag-and-Drop» в палитре свойств нет. Механизм включается тем, что вы назначаете обработчики событий.

Порядок в конфигураторе:

  1. Откройте управляемую форму и выделите элемент, который станет источником (например, таблицу со списком товаров).
  2. В палитре свойств найдите раздел События и создайте обработчик НачалоПеретаскивания. Даже пустой обработчик разрешает старт перетаскивания.
  3. Выделите элемент-приёмник (например, таблицу документа).
  4. У приёмника создайте два обработчика: ПроверкаПеретаскивания и Перетаскивание.

Если источник и приёмник — один и тот же элемент (перетаскиваем строки внутри одной таблицы, чтобы поменять их порядок), все три обработчика назначаются на него же.

Частая ошибка новичка: назначить только событие Перетаскивание у приёмника и забыть ПроверкаПеретаскивания. Без проверки курсор будет показывать запрет, и до обработки отпускания дело не дойдёт.

В событиях-приёмниках есть ещё два параметра — Строка и Поле. Строка указывает, над какой строкой приёмника сейчас курсор, Поле — над какой колонкой. По ним удобно принимать данные не «в конец списка», а в конкретное место.

Перестановка строк внутри одной таблицы

Отдельный случай — не перенос из списка в список, а изменение порядка строк внутри одной таблицы (поднять строку выше или ниже перетаскиванием). Здесь источник и приёмник совпадают, а все три обработчика назначаются на один и тот же элемент.

Логика в событии Перетаскивание такая: Значение указывает на перетаскиваемую строку, Строка — на ту, над которой её отпустили. Вам нужно перенести первую к позиции второй. Так как у строк табличной части нет «порядкового номера» в привычном смысле, порядок задаётся физическим положением строки в коллекции — поэтому перестановку делают через встроенные операции перемещения строк коллекции, а не пересчётом индексов вручную.

Если же в табличной части есть собственная колонка-нумератор (например, НомерСтроки или Порядок), после перестановки её нужно перезаполнить — иначе визуальный порядок и значение в колонке разойдутся.

Где перетаскивание встречается в типовых конфигурациях

В типовых решениях 1С перетаскивание уже используется в нескольких стандартных местах, и логика там та же — три события формы.

  • Подбор товаров. В формах подбора номенклатуры позиции можно перетаскивать из списка в табличную часть документа, а не только добавлять двойным кликом.
  • Файлы и присоединённые документы. В подсистеме работы с файлами внешние файлы перетаскиваются из проводника Windows прямо в карточку объекта. В этом случае в Значение приходит набор переданных файлов.
  • Группировка в иерархических справочниках. Элемент справочника перетаскиванием переносится в другую группу — так меняется родитель.
  • Настройка колонок и порядка строк. Внутри одной таблицы строки перетаскиванием меняют местами.

Отсюда простое правило: если вам нужно воспроизвести поведение «как в типовой», смотрите не на метаданные объекта, а на обработчики событий его формы. Перетаскивание — это всегда свойство формы и её элементов, а не справочника или документа.

Поэтому и переносить механизм из конфигурации в конфигурацию нельзя «копированием объекта». Нужная форма и её обработчики переносятся вместе с элементом формы. Если делаете это через расширение конфигурации , добавьте в заимствованную форму свои обработчики перетаскивания — исходные типовые обработчики при этом остаются на месте.

Пример: переносим позиции из списка в табличную часть

Разберём самый частый сценарий — пользователь выделяет несколько строк в списке номенклатуры и перетаскивает их в таблицу Товары документа.

На источнике (списке) достаточно пустого обработчика — он разрешает старт:

&НаКлиенте
Процедура СписокНоменклатурыНачалоПеретаскивания(Элемент, ПараметрыПеретаскивания, Выполнять)
	// Данные уже в ПараметрыПеретаскивания.Значение.
	// При необходимости можно прервать старт: Выполнять = Ложь;
КонецПроцедуры

На приёмнике (таблице Товары) в проверке снимаем стандартную обработку, чтобы платформа не пыталась обработать бросок по-своему:

&НаКлиенте
Процедура ТоварыПроверкаПеретаскивания(Элемент, ПараметрыПеретаскивания, СтандартнаяОбработка, Строка, Поле)
	СтандартнаяОбработка = Ложь;
КонецПроцедуры

И принимаем данные в событии Перетаскивание. Значение может быть и одной ссылкой, и массивом ссылок — обрабатываем оба случая:

&НаКлиенте
Процедура ТоварыПеретаскивание(Элемент, ПараметрыПеретаскивания, СтандартнаяОбработка, Строка, Поле)
	СтандартнаяОбработка = Ложь;

	Значение = ПараметрыПеретаскивания.Значение;
	Если ТипЗнч(Значение) = Тип("Массив") Тогда
		Для Каждого Ссылка Из Значение Цикл
			ДобавитьТоварВТаблицу(Ссылка);
		КонецЦикла;
	Иначе
		ДобавитьТоварВТаблицу(Значение);
	КонецЕсли;
КонецПроцедуры

&НаКлиенте
Процедура ДобавитьТоварВТаблицу(Номенклатура)
	НоваяСтрока = Объект.Товары.Добавить();
	НоваяСтрока.Номенклатура = Номенклатура;
	НоваяСтрока.Количество = 1;
КонецПроцедуры

Не делайте запрос к серверу внутри цикла по строкам. Если при добавлении нужно подтянуть цену, единицу измерения или остаток, соберите все ссылки в массив и получите данные одним серверным вызовом, а потом разложите по строкам. Иначе перетаскивание двадцати позиций превратится в двадцать обращений к базе.

Сам обработчик Перетаскивание выполняется на клиенте, поэтому обращение к данным информационной базы из него напрямую недоступно — цену и остатки получают серверной процедурой. Это ещё одна причина делать один пакетный вызов вместо запроса на каждую строку.

Почему перетаскивание тормозит или не срабатывает

Жалоба «Drag-and-Drop не работает » почти всегда сводится к нескольким типовым причинам. Разберём их по симптомам.

Диагностика: выберите симптом

Отдельно про скорость. Перетаскивание само по себе лёгкое — тормозит не оно, а то, что вы делаете в обработчике Перетаскивание. Правило простое: клиентский обработчик должен быстро принять данные и один раз сходить на сервер за всем сразу. Любой цикл с обращением к базе внутри — источник фризов.

Если перетаскиваются тысячи строк из динамического списка, помните, что в Значение приедет массив идентификаторов или ссылок на всё выделение. Обрабатывать его имеет смысл порциями, а не строить из него один гигантский запрос.

Копирование или перемещение — как различить

По умолчанию перетаскивание выполняется как перемещение, а при зажатой клавише Ctrl — как копирование. Какое действие выбрал пользователь, видно в свойстве ПараметрыПеретаскивания.Действие в момент броска.

Если ваш приёмник должен принимать данные только одним способом (скажем, всегда копировать, не трогая источник), не полагайтесь на клавишу: явно разрешите нужный вариант в ПроверкаПеретаскивания через свойство ДопустимыеДействия объекта параметров. Тогда пользователь не сможет случайно «переместить» данные и опустошить исходный список.

Разница важна, когда источник и приёмник — разные объекты. При перемещении логично ожидать, что строка из источника исчезнет; при копировании — останется. Приёмник сам отвечает за удаление строки из источника, платформа за него это не делает. Поэтому в сценарии «перенести, а не скопировать» удаление исходной строки пишут отдельно, обычно уже после успешной вставки в приёмник.

Перетаскивание в веб-клиенте и тонком клиенте

Один и тот же код обработчиков работает во всех клиентах, но поведение мыши отличается.

СценарийТонкий клиентВеб-клиент
Перенос строк внутри формыРаботаетРаботает
Перенос между элементами одной формыРаботаетРаботает
Перетаскивание файлов из ОС в формуРаботаетОграничено возможностями браузера
Сенсорный ввод (планшет, тач-экран)Зависит от устройстваПоддержка ограничена

Главное отличие — перетаскивание внешних файлов из проводника. В тонком клиенте это штатная операция. В веб-клиенте перенос файлов зависит от браузера и его настроек безопасности, поэтому критичный сценарий загрузки файлов лучше дублировать обычной кнопкой выбора файла — чтобы пользователь не остался без возможности прикрепить документ.

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

Логика событий при этом одинаковая. Если Drag-and-Drop работает в тонком клиенте и не работает в веб-клиенте, дело не в коде обработчиков, а в ограничениях самого веб-клиента на конкретную операцию — чаще всего на работу с файлами.

Частые вопросы

Чем отличаются события `ПроверкаПеретаскивания` и `Перетаскивание`?
ПроверкаПеретаскивания срабатывает многократно, пока курсор движется над приёмником, — она управляет видом курсора и тем, разрешён ли бросок. Перетаскивание срабатывает один раз, в момент отпускания кнопки мыши, — в нём вы фактически принимаете данные.
Что лежит в `ПараметрыПеретаскивания.Значение`?
Зависит от источника. Для динамического списка — обычно массив ссылок на выделенные элементы, для таблицы формы — данные перетаскиваемой строки. Точный состав удобно посмотреть в отладчике, поставив точку останова в обработчике приёмника.
Как запретить бросок в конкретную строку или колонку?
В обработчике ПроверкаПеретаскивания проверьте параметры Строка и Поле и, если место неподходящее, присвойте ПараметрыПеретаскивания.Действие = ДействиеПеретаскивания.Отмена. Курсор покажет запрет.
Почему курсор при перетаскивании всегда показывает «запрещено»?
Приёмник не разрешил операцию. Проверьте, что назначен обработчик ПроверкаПеретаскивания, в нём снята СтандартнаяОбработка и действие не сброшено в отмену.
Работает ли перетаскивание на планшете и в мобильном браузере?
На сенсорных устройствах и в веб-клиенте поддержка ограничена и зависит от среды. Если сценарий важен, продублируйте его кнопкой или командой меню, чтобы не завязывать всё на жест мышью.