Как реализовать вопрос перед удалением строки в таблице управляемой формы 1С 8.3?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

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

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

Основы работы: почему нельзя просто вызвать вопрос?

Рассмотрим стандартное событие таблицы ПередУдалением. Главная особенность заключается в том, что процедура ПоказатьВопрос является асинхронной. Это значит, что код не останавливается в ожидании ответа пользователя. Если мы просто вызовем вопрос внутри события, платформа продолжит выполнение кода, завершит процедуру и удалит строку еще до того, как пользователь нажмет кнопку «Да» или «Нет».

Чтобы этого избежать, мы всегда должны использовать следующий алгоритм:

  1. В обработчике ПередУдалением устанавливаем параметр Отказ = Истина. Это прерывает стандартный процесс удаления.
  2. Вызываем ПоказатьВопрос, передавая в него описание оповещения (процедуру, которая выполнится после выбора пользователя).
  3. В процедуре оповещения, если пользователь подтвердил действие, выполняем удаление программно.

Вариант 1: Удаление текущей (одной) строки

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

Код на клиенте:


&НаКлиенте
Процедура ТаблицаЗначенийПередУдалением(Элемент, Отказ)
    
    // 1. Блокируем стандартное удаление
    Отказ = Истина;
    
    // 2. Получаем идентификатор текущей строки
    ИдентификаторУдаляемойСтроки = Элементы.ТаблицаЗначений.ТекущиеДанные.ПолучитьИдентификатор();
    
    // 3. Формируем параметры для процедуры завершения
    ПараметрыОповещения = Новый Структура("Идентификатор", ИдентификаторУдаляемойСтроки);
    ОписаниеОповещения = Новый ОписаниеОповещения("РезультатВопросаОбУдалении", ЭтаФорма, ПараметрыОповещения);
    
    // 4. Задаем вопрос
    ПоказатьВопрос(ОписаниеОповещения, "Вы действительно хотите удалить выбранную строку?", РежимДиалогаВопрос.ДаНет);
    
КонецПроцедуры

Обработка ответа:


&НаКлиенте
Процедура РезультатВопросаОбУдалении(Результат, Параметры) Экспорт
    
    Если Результат = КодВозвратаДиалога.Да Тогда
        // Вызываем серверную процедуру для удаления
        УдалитьСтрокуНаСервере(Параметры.Идентификатор);
    КонецЕсли;
    
КонецПроцедуры

&НаСервере
Процедура УдалитьСтрокуНаСервере(Идентификатор)
    
    // Поиск строки в ДанныеФормыКоллекция по идентификатору
    СтрокаДляУдаления = ТаблицаЗначений.НайтиПоИдентификатору(Идентификатор);
    Если СтрокаДляУдаления <> Неопределено Тогда
        ТаблицаЗначений.Удалить(СтрокаДляУдаления);
    КонецЕсли;
    
КонецПроцедуры

Вариант 2: Универсальное удаление нескольких выделенных строк

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

Проанализируем решение, где мы собираем массив идентификаторов всех выделенных строк и передаем их в обработку.


&НаКлиенте
Процедура ТаблицаПередУдалением(Элемент, Отказ)
    
    Отказ = Истина;
    
    // Получаем массив идентификаторов выделенных строк
    МассивИдентификаторов = Элемент.ВыделенныеСтроки;
    
    Если МассивИдентификаторов.Количество() = 0 Тогда
        Возврат;
    КонецЕсли;
    
    ПараметрыОповещения = Новый Структура("ВыделенныеСтроки", МассивИдентификаторов);
    Оповещение = Новый ОписаниеОповещения("ПодтверждениеУдаленияЗавершение", ЭтаФорма, ПараметрыОповещения);
    
    ТекстВопроса = ?(МассивИдентификаторов.Количество() > 1, 
                    "Удалить все выбранные строки (" + МассивИдентификаторов.Количество() + " шт.)?", 
                    "Удалить выбранную строку?");
                    
    ПоказатьВопрос(Оповещение, ТекстВопроса, РежимДиалогаВопрос.ДаНет);
    
КонецПроцедуры

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

&НаСервере
Процедура ВыполнитьУдалениеСтрок(МассивИдентификаторов)
    
    // Создаем копию массива, чтобы избежать проблем с изменением коллекции в цикле
    СтрокиДляУдаления = Новый Массив;
    
    Для Каждого Идентификатор Из МассивИдентификаторов Цикл
        Строка = ТаблицаЗначений.НайтиПоИдентификатору(Идентификатор);
        Если Строка <> Неопределено Тогда
            СтрокиДляУдаления.Добавить(Строка);
        КонецЕсли;
    КонецЦикла;
    
    // Теперь удаляем собранные строки из основной коллекции
    Для Каждого УдаляемаяСтрока Из СтрокиДляУдаления Цикл
        ТаблицаЗначений.Удалить(УдаляемаяСтрока);
    КонецЦикла;
    
КонецПроцедуры

Важные технические нюансы

Рассмотрим дополнительные аспекты, которые помогут сделать решение более профессиональным:

  1. Свойство «Подтверждение удаления»: У элемента формы «Таблица» есть стандартное свойство в палитре свойств. Если вам нужен просто системный вопрос без изменения текста, достаточно включить этот флаг, и писать код не потребуется. Программный метод используется только для кастомизации.
  2. Динамические списки: Если вы работаете с ДинамическимСписком, метод Удалить() у коллекции на сервере не сработает так же, как для таблицы значений. Для удаления записей базы данных потребуется использовать ссылки и метод Объект.Удалить().
  3. Флаг модифицированности: При программном удалении строк свойство формы Модифицированность автоматически устанавливается в Истина. Это важно учитывать, если форма должна закрываться без лишних вопросов при определенных условиях.
  4. Безопасность в циклах: Никогда не удаляйте элементы напрямую из коллекции, по которой в данный момент идет цикл Для Каждого. Это классическая ошибка, приводящая к пропуску строк (так как индексы смещаются). Всегда сначала собирайте объекты в массив, а затем удаляйте вторым циклом, либо используйте обратный цикл (от конца к началу).
  5. Информативность: Для улучшения UX (пользовательского опыта) рекомендуется выводить в вопросе данные из строки, например: "Удалить товар 'Кирпич'?". Для этого в процедуре ПередУдалением получите строковое представление текущих данных и передайте его в ПараметрыОповещения.

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

Таким образом, мы проанализировали ситуацию и создали надежный механизм подтверждения действий пользователя, который корректно работает в клиент-серверной архитектуре 1С:Предприятие 8.3.

← На главную