Как отследить закрытие табличного документа в 1С?

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

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

Проблема стандартного метода Показать()

Разберем ситуацию: когда мы пишем код ТабДок.Показать("Заголовок"), платформа создает стандартное окно для отображения табличного документа. В современных конфигурациях на управляемых формах этот вызов является немодальным. Это означает, что код, следующий сразу за методом Показать(), выполнится мгновенно, не дожидаясь, пока пользователь закроет таблицу. Проанализируем типичный фрагмент кода:


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

Если наша цель — показать предупреждение перед закрытием (например, «Вы уверены, что хотите закрыть отчет?») или выполнить очистку временных данных, метод Показать() нам не подойдет. Нам необходимо решение, позволяющее назначить обработчик события ПередЗакрытием или хотя бы оповещение о закрытии окна.

Решение 1: Использование собственной формы с полем табличного документа

Это самый надежный и «правильный» с точки зрения архитектуры 1С способ. Вместо того чтобы полагаться на встроенные механизмы отображения объекта, мы создадим свою управляемую форму, которая будет выступать контейнером. Рассмотрим этот процесс по шагам.

Шаг 1. Создание формы. Создадим новую обработку или добавим общую форму в конфигурацию. Назовем её ФормаПросмотраТабДока. На форме разместим реквизит с типом ТабличныйДокумент (пусть он называется Результат) и вынесем его на рабочую область формы в виде поля табличного документа.

Шаг 2. Перехват события. Теперь нам доступны все стандартные события формы. Мы можем прописать логику в обработчике ПередЗакрытием:


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

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

Шаг 3. Вызов формы. Теперь вместо метода Показать() мы открываем нашу форму и передаем в неё данные:


ПараметрыФормы = Новый Структура("ТабДок", МойТабличныйДокумент);
ОткрытьФорму("ОбщаяФорма.ФормаПросмотраТабДока", ПараметрыФормы);

Решение 2: Использование системной формы (недокументированный метод)

Если создание отдельной формы кажется избыточным, можно воспользоваться «хитростью» — вызвать системную форму, которую 1С использует внутри себя для отображения табличных документов. Название этой формы — sysForm:spreadsheetdocumentForm. Преимущество здесь в том, что мы можем использовать механизм оповещений о закрытии, не создавая новых объектов в метаданных.

Проанализируем пример кода, предоставленный сообществом:


// Подготовим параметры для системной формы
ПараметрыФормы = Новый Структура;
ПараметрыФормы.Вставить("sheet", ТабличныйДокумент); // Сам документ
ПараметрыФормы.Вставить("ReadOnly", Истина);         // Только чтение
ПараметрыФормы.Вставить("Title", "Мой заголовок");   // Заголовок окна

// Создаем описание оповещения, которое сработает при закрытии
ОповещениеОЗакрытии = Новый ОписаниеОповещения("ПриЗакрытииТаблицы", ЭтотОбъект);

// Открываем системную форму
ОткрытьФорму("sysForm:spreadsheetdocumentForm", ПараметрыФормы, , , , , ОповещениеОЗакрытии);

Разберем, что происходит в этом коде. Мы передаем структуру параметров, где ключ sheet является обязательным — в него помещается сам объект ТабличныйДокумент. Параметр ОповещениеОЗакрытии позволяет нам назначить процедуру, которая выполнится, как только пользователь нажмет на «крестик» или закроет окно иным способом.

Выясним ограничения этого метода. Поскольку это системная форма, у нас нет доступа к её модулю. Мы не можем программно вмешаться в событие ПередЗакрытием и установить Отказ = Истина. Мы можем только узнать постфактум, что форма была закрыта. Также стоит помнить, что использование имен типа sysForm официально не задокументировано, и теоретически платформа может изменить это поведение в будущих релизах.

Решение 3: Перехват через ОписаниеОповещения в управляемом интерфейсе

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

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

  1. Создаем форму контейнер (как в первом решении).
  2. При закрытии формы помещаем табличный документ во Временное хранилище.
  3. Вызываем Закрыть(АдресВоХранилище).
  4. В вызывающей форме ловим этот адрес в процедуре-обработчике оповещения.

Пример реализации в вызывающем коде:


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

&НаКлиенте
Процедура ОбработатьРезультатПослеЗакрытия(РезультатЗакрытия, ДополнительныеПараметры) Экспорт
    Если РезультатЗакрытия <> Неопределено Тогда
        // РезультатЗакрытия может содержать адрес во временном хранилище
        Сообщить("Пользователь завершил работу с документом.");
        ОбновитьДанныеНаФорме(РезультатЗакрытия);
    КонецЕсли;
КонецПроцедуры

Сравнительный анализ методов

Выберем подходящий метод в зависимости от ваших задач:

1. Метод Показать(): Подходит для простого вывода информации «для ознакомления», когда программисту не важно, что будет делать пользователь дальше. События закрытия нет.

2. Системная форма (sysForm): Подходит для быстрой реализации, когда нужно просто получить уведомление о факте закрытия окна без создания лишних объектов в дереве конфигурации. Плюс: минимум кода. Минус: нельзя отменить закрытие вопросом, риск несовместимости с будущими версиями 1С.

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

Дополнительные параметры системной формы

Если вы все же решили использовать sysForm:spreadsheetdocumentForm, посмотрим на расширенный список параметров, которые она может принимать через структуру:

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


ПараметрыФормы = Новый Структура;
ПараметрыФормы.Вставить("sheet", МойТабДок);
ПараметрыФормы.Вставить("ReadOnly", Истина);
ПараметрыФормы.Вставить("Edit", Ложь);
ПараметрыФормы.Вставить("Protection", Истина);
ОткрытьФорму("sysForm:spreadsheetdocumentForm", ПараметрыФормы);

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

← На главную