При разработке интерфейсов в 1С:Предприятие 8.3 часто возникает задача защитить данные от случайного удаления. По умолчанию платформа позволяет удалять строки табличной части без дополнительного подтверждения, что может привести к потере данных, если пользователь случайно нажал клавишу Del. В этой статье мы подробно разберем, как программно перехватить процесс удаления и добавить диалоговое окно с вопросом «Вы действительно хотите удалить выделенные строки?», учитывая особенности асинхронной работы управляемых форм.
На уровне свойств элементов формы в 1С нет простого флажка «Запрашивать подтверждение при удалении». Попытки просто прописать Вопрос() внутри стандартного обработчика события ПередУдалениемСтрок в современном интерфейсе «Такси» не увенчаются успехом, так как платформа требует использования неблокирующих (асинхронных) вызовов. Рассмотрим, как правильно выстроить логику взаимодействия с пользователем.
Многие разработчики на начальном этапе пытаются вызвать диалог внутри процедуры ПередУдалениемСтрок и ожидают, что выполнение кода приостановится. Проанализируем типичный неудачный пример:
&НаКлиенте
Процедура ПередУдалениемСтрок(Элемент, Отказ)
ТекстВопроса = "Удалить строки?";
// Ошибка: процедура продолжится, не дожидаясь ответа пользователя
ОписаниеОповещения = Новый ОписаниеОповещения("Завершение", ЭтотОбъект);
ПоказатьВопрос(ОписаниеОповещения, ТекстВопроса, РежимДиалогаВопрос.ДаНет);
КонецПроцедуры
В данном случае строка будет удалена сразу же, как только закроется процедура ПередУдалениемСтрок, поскольку параметр Отказ по умолчанию равен Ложь, а ПоказатьВопрос не останавливает выполнение кода. К моменту, когда пользователь нажмет «Да» или «Нет», строки в таблице уже не будет.
Для корректной работы нам необходимо применить следующую стратегию:
ПередУдалениемСтрок всегда устанавливать Отказ = Истина. Это принудительно останавливает стандартный механизм удаления платформы.Рассмотрим детально код основной процедуры. Здесь мы подготавливаем данные для передачи в процедуру оповещения.
&НаКлиенте
Процедура ТабличнаяЧастьПередУдалениемСтрок(Элемент, Отказ)
// 1. Отменяем стандартное удаление
Отказ = Истина;
// 2. Проверяем, есть ли выделенные строки
МассивВыделенныхСтрок = Элемент.ВыделенныеСтроки;
Если МассивВыделенныхСтрок.Количество() = 0 Тогда
Возврат;
КонецЕсли;
// 3. Подготавливаем структуру параметров для процедуры завершения
// Нам нужно знать, какие строки удалять и из какого элемента формы
ДопПараметры = Новый Структура;
ДопПараметры.Вставить("МассивВыделенныхСтрок", МассивВыделенныхСтрок);
ДопПараметры.Вставить("ИмяТаблицы", Элемент.Имя);
// 4. Описываем оповещение и показываем вопрос
ТекстВопроса = НСтр("ru='Вы действительно хотите удалить выделенные строки из документа?'");
ОписаниеОповещения = Новый ОписаниеОповещения("ПередУдалениемСтрокЗавершение", ЭтотОбъект, ДопПараметры);
ПоказатьВопрос(ОписаниеОповещения, ТекстВопроса, РежимДиалогаВопрос.ДаНет);
КонецПроцедуры
Теперь выясним важную причину, по которой новички часто сталкиваются с ошибками при удалении. В свойстве Элемент.ВыделенныеСтроки хранятся не индексы (0, 1, 2...), а уникальные идентификаторы строк. Если вы попробуете удалять строки просто по индексу в цикле, то после удаления первой же строки индексы остальных сместятся, и вы либо удалите не те данные, либо получите ошибку «Индекс находится за границами массива».
Для правильного удаления мы будем использовать метод НайтиПоИдентификатору(). Проанализируем код процедуры завершения:
&НаКлиенте
Процедура ПередУдалениемСтрокЗавершение(РезультатВопроса, ДопПараметры) Экспорт
// Если пользователь передумал — ничего не делаем
Если РезультатВопроса <> КодВозвратаДиалога.Да Тогда
Возврат;
КонецЕсли;
МассивИдентификаторов = ДопПараметры.МассивВыделенныхСтрок;
ИмяТЧ = ДопПараметры.ИмяТаблицы;
// Важно: работаем напрямую с коллекцией Объекта через поиск по ID
Для Каждого ИДСтроки Из МассивИдентификаторов Цикл
// Находим строку в табличной части по сохраненному идентификатору
СтрокаТЧ = Объект[ИмяТЧ].НайтиПоИдентификатору(ИДСтроки);
// Если строка найдена (не была удалена ранее программно), удаляем её
Если СтрокаТЧ <> Неопределено Тогда
Объект[ИмяТЧ].Удалить(СтрокаТЧ);
КонецЕсли;
КонецЦикла;
КонецПроцедуры
Разберем несколько тонкостей, которые помогут сделать решение более надежным:
Удалить()) события ПриИзменении табличной части могут не отрабатывать так же, как при интерактивном удалении. Если у вас в документе есть итоги (сумма, количество), после цикла удаления рекомендуется вызвать процедуру их пересчета.ДопПараметры мы передаем имя таблицы. Это позволяет сделать код универсальным, если на форме несколько табличных частей.ПоказатьВопрос на вызов ОбщегоНазначенияКлиент.ПоказатьПодтверждение. Это придаст диалогам стандартный вид, принятый в типовых решениях 1С.В некоторых сценариях проще вообще отказаться от обработки стандартного события удаления. Рассмотрим по шагам этот вариант:
КомандаУдалитьСтроку.Del.В коде такой команды вам не нужно будет использовать Отказ = Истина. Вы просто сначала задаете вопрос, и только при получении ответа «Да» запускаете цикл удаления, описанный выше. Это делает структуру кода более линейной и понятной.
Мы рассмотрели основной механизм создания подтверждения при удалении строк. Главный секрет успеха здесь заключается в связке: принудительная отмена стандартного действия + асинхронный вызов вопроса + удаление через НайтиПоИдентификатору. Используя этот шаблон, вы сможете обеспечить надежность работы пользователей и предотвратить случайную порчу документов.