При разработке на платформе 1С 7.7 с использованием расширений, таких как 1С++, мы часто сталкиваемся с необходимостью перехвата событий форм для реализации сложной логики. Однако иногда возникают ситуации, когда ожидаемое значение поля формы оказывается пустым или недоступным. Давайте разберемся, почему это происходит, и как правильно работать с вычисляемыми полями и внешними классами в 1С++.
Одной из наиболее распространенных причин, по которой значения вычисляемых полей формы могут быть пустыми при попытке чтения в событии ПриОткрытии (СобытиеГМ_ПриОткрытии), является жизненный цикл формы в 1С 7.7. Рассмотрим этот момент подробнее:
ПриОткрытии мы получаем доступ к данным, непосредственно связанным с объектом, которые уже загружены из базы данных (т.е. к его реквизитам). Однако элементы управления формы, включая поля ввода и, в особенности, вычисляемые поля, еще не полностью инициализированы и отрисованы.ПриОткрытии (OnOpen): Это событие срабатывает очень рано, до того, как система полностью подготовит и отобразит визуальные элементы формы. В этот момент значения реквизитов документа доступны, но поля ввода, чьи значения определяются функциями в модуле формы (так называемые «формулы» или «вычисляемые поля»), еще не выполнили свои расчеты. Система просто не успела их проинициализировать, и попытка чтения вернет пустое значение или 0.ПослеОткрытия (AfterOpen): Это событие не является стандартным для 1С 7.7 и обычно добавляется внешними компонентами, такими как 1С++ или FormEx. К моменту вызова этого события визуальная часть формы уже построена, все элементы управления созданы, и все функции-формулы для вычисляемых полей уже отработали. Именно в этом событии мы должны читать значения вычисляемых полей.Чтобы прочитать значение вычисляемого поля, определенного функцией в модуле формы, нам следует перенести логику чтения в событие ПослеОткрытия. Например:
Процедура СобытиеГМ_ПослеОткрытия(Конт) Экспорт
// Теперь форма полностью открыта и вычисляемые поля инициализированы
Сообщить(КонтФормы.Форма.ВысчитываемоеПоле);
// или если хотим вызвать напрямую функцию, которая вычисляет это поле
// ЗначениеПоля = КонтФормы.Форма.ИмяФункцииВычисляющаяПоле();
КонецПроцедуры
Если по каким-то причинам перенос логики в ПослеОткрытия невозможен или неудобен, 1С++ предлагает альтернативный механизм для принудительного вызова функций формы. Мы можем использовать метод контекста Шаблон для прямого вызова функции, которая определена в модуле формы и отвечает за вычисление значения поля.
Метод Шаблон позволяет выполнить произвольный код из модуля формы в заданном контексте. Например, если у нас есть функция ПолучитьВысчитываемоеЗначение(), которая возвращает искомое значение, мы можем вызвать ее следующим образом:
Процедура СобытиеГМ_ПриОткрытии(Конт,ФлагЧтенияНастройки) Экспорт
// Прямой вызов функции, которая вычисляет значение
ЗначениеПоля = Конт.Шаблон("ПолучитьВысчитываемоеЗначение()");
Сообщить(ЗначениеПоля);
// Если поле определено как [ИмяФункции()], то Шаблон также сработает:
// ЗначениеПоля = Конт.Шаблон("[ИмяФункции()]");
КонецПроцедуры
Этот подход позволяет нам получить вычисляемое значение в любой момент, не дожидаясь полной отрисовки поля на форме, поскольку мы напрямую инициируем выполнение функции.
В процессе работы с 1С++ часто возникает необходимость использования внешних обработок (.ert файлов) для определения классов. Это позволяет легче управлять кодом и обновлять его без необходимости изменения конфигурации. Однако, чтобы 1С++ корректно загрузил внешний класс, нам нужно правильно прописать его в файле defcls.ert.
.ert (в отличие от класса, хранящегося в метаданных), мы используем следующий синтаксис в defcls.ert:
class ИмяКласса = "путь_к_файлу\КлассПерехватСобытий.ert" {}
Здесь ИмяКласса — это имя, под которым класс будет доступен в коде 1С, а путь_к_файлу\КлассПерехватСобытий.ert — это полный или относительный путь к файлу обработки.
КлассПерехватСобытий.ert находится в подпапке Classes относительно каталога базы, запись будет такой:
class КлассПерехватСобытий = ".\Classes\КлассПерехватСобытий.ert" {}
Обратите внимание, что . (точка) обозначает текущий каталог (каталог базы данных 1С).
@MD: Если же мы хотим, чтобы 1С++ принудительно искал обработку внутри конфигурации (метаданных), мы используем ключевое слово @MD:
class КлассПерехватСобытий = КлассПерехватСобытий@MD {}
В этом случае файл defcls.ert будет игнорировать внешние .ert файлы с таким же именем и всегда обращаться к обработке из метаданных. Если мы планируем править код во внешней обработке и хотим, чтобы эти изменения подхватывались, мы должны убрать привязку к @MD.
Возможно, вы замечали, что изменения, внесенные во внешний файл класса 1С++, не всегда сразу подхватываются системой, даже если используется TurboMD. Давайте выясним причину этого поведения:
.ert файла или из метаданных), компилирует его во внутреннее представление и затем кэширует в памяти. Это означает, что после первой загрузки класса, 1С++ использует уже скомпилированную версию.Если ваша задача состоит в более сложном управлении правами или перехвате низкоуровневых событий формы (например, нажатия клавиш, изменение размеров, программное закрытие формы), одного 1С++ может быть недостаточно. Часто в таких случаях используется внешняя компонента FormEx.
ПриЗаписи (или событие нажатия кнопки "Записать") еще до того, как сработает стандартный механизм записи 1С, провести свои проверки и, при необходимости, отменить запись или переключить форму в режим "только просмотр".Form), что может упростить доступ к атрибутам формы через точку и сделать код более читаемым, хотя это не решает проблему "пустых значений" в ПриОткрытии для вычисляемых полей.Для успешного решения описанных проблем и эффективной работы с перехватчиками событий 1С++ в 1С 7.7, мы рекомендуем выполнить следующие шаги:
ПослеОткрытия: Перенесите логику чтения значений вычисляемых полей в событие ПослеОткрытия (СобытиеГМ_ПослеОткрытия), которое срабатывает после полной инициализации и отрисовки формы.Шаблон: Если перенос в ПослеОткрытия невозможен, используйте метод контекста Конт.Шаблон("[ИмяФункции()]") для принудительного вызова функции, которая вычисляет значение поля, получая результат напрямую.defcls.ert: Убедитесь, что синтаксис для подключения внешнего файла класса .ert корректен. Используйте запись вида class ИмяКласса = ".\Classes\КлассПерехватСобытий.ert" {}, избегая привязки к @MD, если вы хотите использовать внешний файл.Следуя этим рекомендациям, мы сможем эффективно использовать возможности 1С++ для создания гибких и мощных решений в 1С 7.7, избегая распространенных проблем с доступом к данным формы и управлением классами.