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