Как определить тип группового контекста в 1С 7.7?

Программист 1С v7.7 IT и автоматизация бизнеса
← На главную

Разработчики, пришедшие в 1С:Предприятие 7.7 из более современных версий платформы (например, 1С 8.3), часто сталкиваются с неочевидным поведением системы при работе с контекстами программных модулей. В «семерке» существует универсальное понятие ГрупповойКонтекст. Этот тип данных возвращается системной функцией ТипЗначенияСтр() как для открытой формы документа или справочника, так и для модуля проведения, модуля отчета или таблицы значений.

В этой статье мы подробно разберем, почему стандартная функция ТипЗначенияСтр() возвращает лишь малоинформативную строку "ГрупповойКонтекст", и рассмотрим практические методы, которые помогут нам безошибочно определить реальный тип объекта, стоящего за этим контекстом.

В чем заключается проблема неопределенности контекста?

Когда мы передаем контекст (ключевое слово Контекст) из формы или модуля в глобальный модуль или внешнюю обработку, принимающая процедура видит его как тип ГрупповойКонтекст. Платформа 1С 7.7 не предоставляет прямого метода вроде ТипЗнч() из восьмой версии, который мог бы сразу сказать нам: «Перед вами форма документа Реализация» или «Это модуль проведения справочника Контрагенты».

Если мы попытаемся вызвать метод, не предназначенный для конкретного контекста (например, обратимся к методу Модифицированность() в модуле проведения документа, где интерфейсной формы просто нет), система завершит работу с критической ошибкой выполнения. Поэтому перед разработчиком встает задача гарантированной и безопасной идентификации типа группового контекста.

Давайте пошагово проанализируем основные способы решения этой проблемы.

Решение №1. Использование конструкции Попытка — Исключение для проверки уникальных свойств

Самый распространенный и проверенный временем способ в рамках стандартных возможностей платформы 1С 7.7 — это последовательный перебор уникальных атрибутов и методов различных объектов с помощью конструкции Попытка — Исключение. Если обращение к специфическому методу не вызывает ошибку, значит, мы имеем дело с соответствующим типом объекта.

Давайте рассмотрим пример написания универсальной функции в глобальном модуле, которая проверяет свойства контекста:


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

Этот подход работает надежно, хотя и выглядит громоздко. Он позволяет «отсеять» неподходящие типы и локализовать область применения переданного контекста.

Решение №2. Быстрое разделение контекста формы и модуля проведения

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

В контексте открытой интерактивной формы всегда существует предопределенный системный атрибут Форма. В программном контексте проведения его нет. Таким образом, самым простым и элегантным способом разделения контекстов будет следующая проверка:


ЭтоКонтекстФормы = 0;
Попытка
    // Пытаемся обратиться к системному свойству Форма
    ВременнаяСсылка = Конт.Форма;
    ЭтоКонтекстФормы = 1;
Исключение
    // Свойства "Форма" нет, значит, мы в модуле объекта (проведение, запись и т.д.)
    ЭтоКонтекстФормы = 0;
КонецПопытки;

Если ЭтоКонтекстФормы = 1 Тогда
    // Здесь мы можем безопасно использовать методы формы
    Если Конт.Модифицированность() = 1 Тогда
        Предупреждение("Внимание! Данные формы изменены.");
    КонецЕсли;
КонецЕсли;

Решение №3. Анализ внутренней сигнатуры строки через ЗначениеВСтрокуВнутр()

Еще один продвинутый способ анализа контекста без провоцирования системных ошибок — исследование строкового представления объекта в специальном формате 1С. Функция ЗначениеВСтрокуВнутр(Конт) возвращает служебную системную информацию в текстовом виде.

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

Решение №4. Контроль динамического изменения типа контекста

Важно помнить об одной критической особенности платформы 1С 7.7. Тип группового контекста может изменяться непосредственно во время работы программы:

  1. Пока форма открыта интерактивно, функция ТипЗначения(Конт) возвращает числовое значение 100 (что соответствует групповому контексту), а строковая функция ТипЗначенияСтр(Конт) возвращает "ГрупповойКонтекст".
  2. Как только пользователь закрывает форму, ссылка на этот контекст в нашей переменной (например, если мы сохранили контекст формы в переменной глобального модуля) не очищается автоматически, однако ее тип динамически меняется на 0 ("Неопределенный").

Если мы попытаемся вызвать любой метод у переменной, содержащей ссылку на закрытую форму, программа аварийно завершится. Поэтому перед анализом контекста всегда выполняем проверку на его «жизненное состояние»:


Если ТипЗначения(ПроверяемыйКонтекст) = 100 Тогда
    // Форма гарантированно открыта, работа с контекстом безопасна
    ПроверяемыйКонтекст.Заголовок("Новый заголовок формы");
Иначе
    // Форма уже закрыта пользователем, контекст недействителен
    Сообщить("Связь с контекстом формы утеряна!", "!");
КонецЕсли;

Решение №5. Использование возможностей внешних компонент (FormEx и 1С++)

Если ваша конфигурация использует популярные внешние компоненты, задача определения типа контекста решается мгновенно и элегантно, без использования конструкций Попытка — Исключение.

Например, библиотека FormEx предоставляет специализированный объект РасширениеФормы. Передав ему наш контекст, мы можем легко получить детальную информацию о типе метаданных:


// Пример использования FormEx для определения типа объекта
Сервис = СоздатьОбъект("Сервис");
Попытка
    Расширение = СоздатьОбъект("РасширениеФормы");
    Расширение.УстановитьФорму(Конт.Форма);
    ПолныйТип = Расширение.ПолныйТипОбъекта(); 
    // Возвратит, например, "Документ.Реализация.ФормаДокумента"
    Сообщить("Тип контекста: " + ПолныйТип);
Исключение
    Сообщить("Контекст не содержит форму.");
КонецПопытки;

Архитектурные рекомендации по проектированию проведения документов

Разбирая проблему определения контекста, важно затронуть и архитектурный аспект. Часто необходимость разделения контекста формы и модуля проведения возникает из-за неверного проектирования логики программы.

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

Правильным решением будет сбор всех необходимых параметров от пользователя в модуле формы до момента начала проведения. Затем эти параметры можно передать в процедуру проведения штатным образом через второй параметр метода Провести():


// В модуле формы документа перед проведением:
СписокПараметров = СоздатьОбъект("СписокЗначений");
СписокПараметров.ДобавитьЗначение(ВведенноеПользователемЗначение, "ДопПараметр");

// Вызываем проведение с передачей списка параметров
Если Провести(0, СписокПараметров) = 1 Тогда
    // Документ успешно проведен
КонецЕсли;

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


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

Таким образом, мы рассмотрели все доступные и безопасные способы определения типа группового контекста в среде 1С:Предприятие 7.7. Используйте эти методы для создания надежного и отказоустойчивого кода!

← На главную