В процессе разработки в среде 1С:Предприятие для обычного приложения (толстый клиент) программисты часто сталкиваются со специфическим поведением метода Показать() объекта ТабличныйДокумент. Суть проблемы заключается в том, что при программном формировании и выводе отчета или печатной формы в отдельное системное окно, платформа не считает документ «измененным». Как следствие, если пользователь решит закрыть это окно, система не предложит ему сохранить результат работы. В этой статье мы подробно разберем, почему так происходит и какими способами можно «взвести» флаг модифицированности (ту самую «звездочку» в заголовке), чтобы гарантировать сохранность данных.
Для начала давайте выясним причину, по которой стандартный метод Показать() ведет себя именно так. В обычном приложении, когда мы вызываем ТабличныйДокумент.Показать(), платформа создает системное окно предварительного просмотра. Особенность этого окна в том, что оно отслеживает исключительно интерактивные изменения.
Разберем по шагам: когда мы пишем код для заполнения ячеек, установки шрифтов или границ, платформа воспринимает это как процесс формирования документа. С точки зрения логики 1С, документ готов, и он «чист». Только если пользователь после открытия окна сам нажмет клавишу F2, введет текст в ячейку или изменит формат через меню, платформа установит внутренний флаг Модифицированность в значение Истина. Программного свойства Модифицированность у самого объекта ТабличныйДокумент не существует, оно является свойством объекта Форма.
Самым правильным и «чистым» с точки зрения архитектуры решением является отказ от метода Показать() в пользу вывода документа на специально созданную форму. Рассмотрим, как это реализовать, чтобы сохранить удобство (независимость окна от основной обработки).
Многие разработчики опасаются, что форма закроется сразу после того, как будет закрыта вызвавшая ее обработка. Чтобы избежать этого, мы воспользуемся свойством ЗакрыватьПриЗакрытииВладельца. Проанализируем пример кода:
// Создаем или получаем форму, в которой размещен элемент "ПолеТабличногоДокумента"
НоваяФорма = ПолучитьФорму("ВнешняяОбработка.МояОбработка.Форма.ФормаПечати");
// Переносим сформированный документ в элемент управления на форме
НоваяФорма.ЭлементыФормы.ПолеТабличногоДокумента.Вывести(СформированныйТабДок);
// Устанавливаем признак модифицированности самой формы
НоваяФорма.Модифицированность = Истина;
// Важный нюанс: отвязываем форму от родительской обработки
НоваяФорма.ЗакрыватьПриЗакрытииВладельца = Ложь;
// Показываем форму пользователю
НоваяФорма.Открыть();
В данном случае, установив НоваяФорма.Модифицированность = Истина, мы принудительно заставляем систему выдать диалоговое окно «Сохранить изменения?» при попытке закрытия. Это надежный способ, работающий в рамках стандартной логики платформы.
Если вы работаете в типовой конфигурации (например, УПП или БП 2.0), то создавать свою форму для каждого отчета не обязательно. Проанализируем ситуацию: в таких конфигурациях уже существуют общие формы для отображения печатных листов. Мы можем использовать их, вызывая через ОткрытьФорму.
Рассмотрим пример обращения к системным механизмам:
ПараметрыФормы = Новый Структура;
ПараметрыФормы.Вставить("ТабличныйДокумент", МойТабДок);
ПараметрыФормы.Вставить("Заголовок", "Отчет по продажам");
// Открываем типовую форму просмотра
ФормаПечати = ОткрытьФорму("ОбщаяФорма.ПечатьДокументов", ПараметрыФормы);
// Теперь мы можем программно обратиться к объекту формы и взвести флаг
ФормаПечати.Модифицированность = Истина;
Этот подход экономит время на разработку дизайна форм, так как типовые формы уже содержат кнопки печати, сохранения в PDF/Excel и настройки масштаба.
Иногда возникают ситуации, когда проект настолько ограничен, что добавление новых форм в метаданные невозможно или крайне нежелательно. В таких случаях программисты используют «хакерский» метод — эмуляцию действий пользователя с помощью Windows Script Host. Выясним, как это работает.
Суть метода: сразу после вызова Показать() мы отправляем в активное окно последовательность клавиш, которая заставит платформу поверить, что пользователь что-то изменил. Посмотрим на пример кода:
ТабДок.Показать("Заголовок окна");
// Создаем COM-объект для управления вводом
WshShell = Новый COMОбъект("WScript.Shell");
// Даем небольшую паузу, чтобы окно успело отрисоваться и получить фокус
// Внимание: метод не всегда стабилен в терминальных сессиях!
WshShell.SendKeys("{F2}"); // Нажимаем F2 (вход в режим редактирования ячейки)
WshShell.SendKeys("{ENTER}"); // Нажимаем Enter (завершение редактирования)
Важное предупреждение: этот метод считается «грязным». Если в момент срабатывания скрипта пользователь переключит окно, нажатия клавиш уйдут в другое приложение. Используйте его только в крайнем случае.
При работе с модифицированностью табличного документа обязательно проверьте следующие настройки, иначе ни один из вышеперечисленных способов не сработает:
ТабДок.ТолькоПросмотр = Истина, флаг модифицированности не взведется. Система логично предполагает, что если документ нельзя менять, то и сохранять там нечего. Для работы диалога сохранения установите ТолькоПросмотр = Ложь.SendKeys).Показать() выполняется асинхронно. Код, написанный после этого метода, продолжает выполняться немедленно.Мы рассмотрели несколько стратегий управления состоянием табличного документа. Выбор конкретного метода зависит от ваших задач:
Для универсальных инструментов: Лучше всего подходит создание собственной независимой формы с установленным свойством ЗакрыватьПриЗакрытииВладельца = Ложь. Это дает полный контроль над событиями закрытия и свойством Модифицированность.
Для типовых решений: Рациональнее использовать ОбщаяФорма.ПечатьДокументов или аналогичные объекты конфигурации, которые уже «умеют» обрабатывать модифицированность и предоставляют пользователю привычный интерфейс.
Для быстрой правки «на коленке»: Можно рассмотреть вариант с WScript.Shell, но помните о рисках потери фокуса окна.
Проанализировав эти подходы, мы видим, что отсутствие прямого свойства у объекта ТабличныйДокумент не является непреодолимым препятствием, если понимать разницу между объектом данных и объектом отображения (формой) в архитектуре 1С.