Перетаскивание объектов в управляемых формах 1С: способы и рабочий код

· 10 мин

Содержание

Перетаскивание (Drag & Drop) в 1С 8.3 делают не кодом «с нуля», а через штатные события управляемой формы: НачалоПеретаскивания, ПроверкаПеретаскивания и Перетаскивание. Чтобы сделать перетаскивание, достаточно разрешить его у элемента-таблицы в свойствах и описать два-три клиентских обработчика — строки начнут переноситься мышью.

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

Рабочих способов три: штатный механизм управляемой формы для списков и табличных частей, HTML-поле для канбана и свободного размещения карточек, внешняя компонента для нестандартных сценариев. Ниже — какой когда брать, с проверяемым кодом для первого (он закрывает большинство задач).

Как платформа обрабатывает перетаскивание

Перетаскивание в управляемой форме — это цепочка из четырёх событий у элемента формы. Два из них срабатывают у источника (откуда тащим), два — у приёмника (куда бросаем):

  • 🎯 НачалоПеретаскивания — у источника, когда пользователь «взял» строку. Здесь вы кладёте в перенос нужные данные.
  • 🔎 ПроверкаПеретаскивания — у приёмника, пока курсор движется над целью. Здесь вы решаете, разрешить ли бросок и каким будет действие (перемещение или копирование).
  • 📥 Перетаскивание — у приёмника, в момент броска. Здесь выполняется основная работа: добавить строку, сдвинуть, переназначить группу.
  • 🔚 ОкончаниеПеретаскивания — у источника, после завершения. Нужно редко — например, чтобы удалить строку из источника при перемещении.

Данные между событиями ходят через объект ПараметрыПеретаскивания. У него два ключевых свойства: Значение — то, что переносим (вы задаёте его сами в НачалоПеретаскивания), и Действие — тип операции из набора ТипДействияПеретаскивания (Перемещение, Копирование, Отмена, НеОбрабатывать).

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

Какой способ перетаскивания выбрать под задачу?

Включаем перетаскивание и переставляем строки мышью

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

Шаг 1. Разрешите перетаскивание у элемента. В конфигураторе откройте форму, выделите элемент-таблицу Задачи и в палитре свойств (группа «Использование») включите начало перетаскивания у источника и приём у приёмника — для одной таблицы это один и тот же элемент. Названия свойств в разных версиях платформы могут отличаться; ориентируйтесь на пункты, отвечающие за перетаскивание.

Шаг 2. Запомните, какую строку тащим. В НачалоПеретаскивания положите в перенос идентификатор текущей строки:

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

Элементы.Задачи.ТекущаяСтрока возвращает идентификатор строки — по нему позже найдём её в коллекции.

Шаг 3. Разрешите бросок. В ПроверкаПеретаскивания задайте действие, иначе курсор покажет «запрещено»:

&НаКлиенте
Процедура ЗадачиПроверкаПеретаскивания(Элемент, ПараметрыПеретаскивания, СтандартнаяОбработка, Строка, Поле)
    ПараметрыПеретаскивания.Действие = ТипДействияПеретаскивания.Перемещение;
КонецПроцедуры

Шаг 4. Переставьте строку в момент броска. Параметр Строка — идентификатор строки-приёмника (или Неопределено, если бросили не на строку):

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

    ИсходнаяСтрока = Задачи.НайтиПоИдентификатору(ПараметрыПеретаскивания.Значение);
    Если ИсходнаяСтрока = Неопределено Тогда
        Возврат;
    КонецЕсли;

    Если Строка = Неопределено Тогда
        // бросили на пустое место — ставим в конец
        Смещение = Задачи.Количество() - 1 - Задачи.Индекс(ИсходнаяСтрока);
    Иначе
        СтрокаПриёмник = Задачи.НайтиПоИдентификатору(Строка);
        Смещение = Задачи.Индекс(СтрокаПриёмник) - Задачи.Индекс(ИсходнаяСтрока);
    КонецЕсли;

    Задачи.Сдвинуть(ИсходнаяСтрока, Смещение);
КонецПроцедуры

Весь код — на клиенте: события перетаскивания клиентские, к базе здесь не обращаемся. Если порядок нужно сохранить в реквизите (например, Приоритет), пересчитайте его одним проходом после сдвига и запишите на сервере один раз — не на каждое движение мыши.

Табличная часть документа работает так же: выводите её на форму таблицей и вешаете те же обработчики на элемент ТЧ. Ссылочная коллекция в памяти ведёт себя как таблица значений.

Перенос элементов между двумя списками и в дерево

Второй по частоте сценарий — две таблицы рядом: слева «Доступные», справа «Выбранные», элементы перетаскиваются из одной в другую. Здесь важно передать между коллекциями не идентификатор (он действителен только внутри своей таблицы), а сами значения полей.

В источнике соберите данные строки в структуру:

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

В приёмнике добавьте строку и заполните её из структуры — с проверкой типа, чтобы случайный перенос файла или элемента из другого списка не уронил обработчик:

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

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

    НоваяСтрока = Выбранные.Добавить();
    ЗаполнитьЗначенияСвойств(НоваяСтрока, Данные);
КонецПроцедуры

Если перенос односторонний (элемент должен исчезнуть из «Доступных»), удалите исходную строку в ОкончаниеПеретаскивания источника — но только когда Действие равно Перемещение, а не Отмена.

Дерево и иерархия. Когда нужно перетаскиванием подчинять элементы группам (иерархический справочник, дерево значений), цель — строка-группа. У иерархического динамического списка штатная обработка часто уже меняет родителя сама: оставьте СтандартнаяОбработка = Истина и проверьте поведение. Если нужна своя логика (запрет вложенности, пересчёт итогов) — перехватывайте бросок и в Строка получите узел-приёмник, которому назначаете нового родителя.

HTML-поле для канбана и свободного перетаскивания

Когда штатных таблиц мало — нужен канбан с колонками, перетаскивание плиток по сетке, своя анимация — берут поле вида «Поле HTML документа». Внутри него работает обычный веб: верстаете карточки, вешаете на них стандартный HTML5 drag & drop.

Минимальный каркас разметки внутри поля:

<div class="card" draggable="true" ondragstart="onStart(event)">Заявка №1</div>
<div class="col" ondragover="event.preventDefault()" ondrop="onDrop(event)">В работе</div>

Логика переноса (dragstart, dragover, drop) целиком живёт в JS внутри HTML-поля — платформу она не касается, пока вы перекладываете карточки визуально. Сложность только в обратной связи: когда карточка переехала в другую колонку, это изменение нужно вернуть в 1С, чтобы записать новый статус.

Способ обмена зависит от версии платформы и вида поля. Рабочий общий приём — отдавать результат из HTML в 1С через переход по служебной ссылке с закодированными данными, а на стороне формы ловить это событие поля и разбирать параметры. Конкретную привязку сверяйте со справкой по вашему релизу: детали обмена HTML-поля с формой между версиями менялись.

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

Внешние компоненты и перетаскивание файлов из проводника

Если задача выходит за рамки форм — нужен нестандартный виджет, интеграция с рабочим столом ОС, особая обработка жестов — пишут внешнюю компоненту на технологии Native API. Она рисует свой интерфейс и обрабатывает перетаскивание собственным кодом, а в 1С отдаёт готовый результат. Это самый трудоёмкий путь: оправдан, когда первые два способа не закрывают сценарий.

Отдельный случай — перетаскивание файлов из проводника Windows прямо в форму. Платформа это поддерживает: при броске файла срабатывает тот же Перетаскивание, а в ПараметрыПеретаскивания.Значение приходят данные о файле (или массив, если тянули несколько). Тип значения здесь не такой, как при переносе строк, поэтому обязательно проверяйте его через ТипЗнч() перед обработкой и ветвите код: строки — одно, файлы — другое.

В веб-клиенте перетаскивание файлов из ОС ограничено тем, что разрешает браузер и настройки безопасности, — проверяйте сценарий в той среде, где работают пользователи, а не только в тонком клиенте.

Перетаскивание в больших списках: производительность

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

  • ⚡ Держите обработчики перетаскивания клиентскими. Все расчёты позиции делайте в памяти, без обращения к базе.
  • 💾 Пишите результат один раз — в момент броска, а не на каждом событии. Если переставляете много строк, сохраняйте новый порядок пакетом через один серверный вызов.
  • 🚫 Не пытайтесь переупорядочивать мышью динамический список: он читается из базы порциями, и «перетащенный» порядок всё равно собьётся при обновлении. Для ручного порядка используйте таблицу значений на форме или реквизит-порядок у объекта.
  • 📉 Не перечитывайте всю таблицу после броска. Меняйте в коллекции только затронутые строки — сдвиг и перенос этого не требуют.

Если пользователю нужно расставить приоритеты среди сотен позиций, не грузите их все в одну форму: дайте фильтр или постраничный вывод, а перетаскивание оставьте в пределах видимой порции.

Что собирают на практике

Перетаскивание редко делают ради самого эффекта — за ним почти всегда стоит понятная задача. Типовые сценарии и способ под каждый:

  • 📋 Ручной приоритет списка. Менеджер перетаскиванием расставляет задачи, заявки, этапы по важности. Таблица значений на форме, сдвиг строки, запись реквизита-порядка при закрытии. Способ 1.
  • ↔️ Выбор из доступного. Две таблицы: слева весь справочник номенклатуры или сотрудников, справа отобранные позиции. Элементы перетягивают слева направо. Способ 1, перенос через структуру.
  • 🗂️ Раскладка по группам. Перетаскиванием подчиняют элементы папкам в иерархическом справочнике или узлам дерева. Способ 1 с деревом.
  • 🧩 Канбан по статусам. Карточки заявок или задач переезжают между колонками «Новая → В работе → Закрыта», смена колонки меняет статус в базе. HTML-поле, способ 2.
  • 📎 Прикрепление файлов . Документы тянут из проводника прямо в форму объекта и сохраняют как присоединённые файлы. Способ 3, обработка файлового переноса.

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

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

Чаще всего «не тащится» по одной из пяти причин. Найдите свой симптом:

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

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

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

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