Как задать вопрос пользователю через ПоказатьВопрос в обработчике ПередНачаломДобавления

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

При переходе на немодальный интерфейс и работу в управляемых формах 1С разработчики часто сталкиваются с проблемой вызова диалоговых окон в стандартных событиях табличных частей, таких как ПередНачаломДобавления или ПередНачаломИзменения. В модальном режиме выполнение кода приостанавливалось на функции Вопрос(), что позволяло напрямую присвоить параметру Отказ значение Истина в зависимости от ответа пользователя.

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

Рассмотрим, как правильно обойти это ограничение платформы и реализовать интерактивный опрос пользователя при добавлении и редактировании строк табличной части.

Причина проблемы и архитектурное ограничение

Проанализируем механику работы события. Когда пользователь нажимает кнопку «Добавить» или клавишу Insert, платформа 1С вызывает обработчик ПередНачаломДобавления. Платформа ожидает, что после завершения этой процедуры параметр Отказ сразу примет итоговое значение.

Если вызвать ПоказатьВопрос(), обработчик завершается мгновенно, и платформа добавляет строку. Ответ пользователя приходит позже в отдельную процедуру оповещения (Callback), однако вернуть управление в уже завершенное событие ПередНачаломДобавления невозможно.

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

Решение 1: Программное добавление строки после ответа пользователя

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

Рассмотрим код обработчика события и процедуры обратного вызова:


&НаКлиенте
Процедура ДопКомплектацияПередНачаломДобавления(Элемент, Отказ, Копирование, Родитель, Группа, Параметр)
    
    // Прерываем стандартное добавление строки платформой
    Отказ = Истина;
    
    // Сохраняем необходимые контекстные параметры (например, факт копирования)
    ДополнительныеПараметры = Новый Структура;
    ДополнительныеПараметры.Вставить("Копирование", Копирование);
    
    Оповещение = Новый ОписаниеОповещения("ПослеОтветаПользователяПриДобавлении", ЭтотОбъект, ДополнительныеПараметры);
    
    ТекстВопроса = НСтр("ru = 'Для выполнения этой операции необходимо записать документ. Записать?'");
    ПоказатьВопрос(Оповещение, ТекстВопроса, РежимДиалогаВопрос.ДаНет);
    
КонецПроцедуры

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

В данном сценарии мы отменяем стандартный вызов, а при получении ответа Да самостоятельно записываем объект и добавляем строку в коллекцию табличной части.

Решение 2: Обработка редактирования существующей строки (ПередНачаломИзменения)

Для события ПередНачаломИзменения логика аналогична, однако для перевода существующей строки в режим редактирования используется метод элемента формы ИзменитьСтроку().

Рассмотрим реализацию унифицированного вызова для добавления и изменения строк:


&НаКлиенте
Процедура ДопКомплектацияПередНачаломИзменения(Элемент, Отказ)
    
    Отказ = Истина;
    
    ПараметрыОповещения = Новый Структура;
    ПараметрыОповещения.Вставить("Элемент", Элемент);
    ПараметрыОповещения.Вставить("ВидВызова", "Изменение");
    
    Оповещение = Новый ОписаниеОповещения("ПослеОтветаПользователя", ЭтаФорма, ПараметрыОповещения);
    
    ТекстВопроса = НСтр("ru = 'Вы уверены, что хотите внести изменения в строку?'");
    ПоказатьВопрос(Оповещение, ТекстВопроса, РежимДиалогаВопрос.ДаНет);
    
КонецПроцедуры

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

Метод Элемент.ИзменитьСтроку() переводит активированную строку табличной части в режим редактирования по аналогии с нажатием клавиши F2 или двойным кликом мыши.

Решение 3: Использование флага-переменной формы

Альтернативный подход заключается в использовании переменной модуля формы в качестве флага разрешения. Это позволяет избежать прямого вызова методов ДобавитьСтроку() или ИзменитьСтроку() и повторно передать управление стандартным обработчикам платформы.

  1. Объявляем клиентскую переменную формы РазрешеноИзменение.
  2. В обработчике события проверяем флаг: если он равен Ложь, ставим Отказ = Истина и задаем вопрос.
  3. При согласии пользователя устанавливаем РазрешеноИзменение = Истина и вызываем Элементы.Таблица.ИзменитьСтроку().
  4. При повторном входе в обработчик проверка проходит, параметр Отказ остается Ложь, а флаг сбрасывается обратно в Ложь.

Посмотрим на пример кода с флагом:


&НаКлиенте
Перем РазрешеноИзменение;

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

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

Альтернативные архитектурные решения

Если работа со стандартными событиями таблицы вызывает сложности из-за асинхронности, проанализируем альтернативные способы реализации:

  1. Замена стандартных кнопок пользовательскими командами: Отключите стандартные кнопки добавления и изменения в свойствах таблицы. Создайте собственную команду формы «Добавить строку». В ее обработчике параметр Отказ отсутствует, что позволяет свободно использовать ПоказатьВопрос() или асинхронные функции без отмены стандартных событий.
  2. Перенос проверки в событие ПриНачалеРедактирования: Задавайте вопрос в момент, когда строка уже создана или открыта на редактирование. Если пользователь отказался от редактирования, вызовите метод Элементы.Таблица.ОтменитьРедактирование(). Это автоматически удалит вновь созданную строку или отменит изменения в существующей.

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

← На главную