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

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

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

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

Метод 1. Использование встроенной функции АктивныйЭлемент()

Самый простой и очевидный способ, предоставляемый штатным функционалом 1С 7.7, — это использование функции контекста формы АктивныйЭлемент(). Данный метод возвращает строковое имя элемента диалога, который в данный момент находится в фокусе.

Давайте рассмотрим, как это реализовать на практике. В формуле каждого интерактивного поля на форме мы прописываем вызов нашей общей процедуры без параметров:

ПриИзмененииПолейВзаимозачета()

А в модуле формы описываем саму процедуру следующим образом:


Процедура ПриИзмененииПолейВзаимозачета()
    ИмяАктивногоПоля = Форма.АктивныйЭлемент();
    Сообщить("Пользователь изменил поле с идентификатором: " + ИмяАктивногоПоля);
КонецПроцедуры

Важное ограничение этого метода: функция АктивныйЭлемент() работает безупречно только в том случае, если триггером изменения послужило нажатие клавиши Enter. Если же пользователь изменил значение поля ввода и сразу кликнул мышкой на другой элемент формы, фокус ввода успевает переместиться до того, как отработает формула предыдущего поля. В результате функция АктивныйЭлемент() вернет имя уже нового активного элемента, что приведет к неверной обработке логики.

Метод 2. Передача идентификатора строкой и магия функции Шаблон()

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

ПриИзмененииПолейВзаимозачета("мПоле")

Теперь в процедуру приходит точное имя переменной. Но как прочитать её значение, имея на руках только строковое имя? Первое, что приходит в голову — воспользоваться функцией Шаблон():


Процедура ПриИзмененииПолейВзаимозачета(ИмяРеквизита)
    ЗначениеАтрибута = Шаблон("[" + ИмяРеквизита + "]");
КонецПроцедуры

Однако этот подход таит в себе скрытую угрозу. Функция Шаблон() вычисляет выражение внутри квадратных скобок в контексте модуля формы, но всегда **принудительно преобразует результат в строковый тип данных**. Если ваш реквизит имел тип «Число», «Дата» или являлся ссылкой на справочник или документ, вы получите лишь его текстовое представление. Работать со ссылочными типами данных или выполнять математические операции после такого преобразования станет невозможно.

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


Процедура ПриИзмененииПолейВзаимозачета(ИмяРеквизита)
    // Упаковываем и распаковываем объект для сохранения оригинального типа данных
    ЗначениеАтрибута = ЗначениеИзСтрокиВнутр(Шаблон("[ЗначениеВСтрокуВнутр(" + ИмяРеквизита + ")]"));
    
    // Теперь ЗначениеАтрибута имеет правильный тип (Справочник, Число, Дата и т.д.)
    Сообщить("Тип полученного значения: " + ТипЗначенияСтр(ЗначениеАтрибута));
КонецПроцедуры

Проанализируем, как работает эта строка кода. Сначала динамически формируется выражение вида [ЗначениеВСтрокуВнутр(мПоле)]. Функция Шаблон() вычисляет его в контексте формы. Происходит сериализация значения реквизита во внутренний строковый идентификатор 1С. Полученная строка возвращается из функции Шаблон() и передается в ЗначениеИзСтрокиВнутр(), которая мгновенно восстанавливает полноценный объект со всеми его свойствами и типами.

Метод 3. Динамическая запись значения по имени переменной

А что делать, если нам требуется не только прочитать, но и записать новое значение в переменную формы по её строковому имени? Встроенные методы платформы Форма.УстановитьАтрибут() работают только для тех реквизитов, которые жестко привязаны к метаданным конфигурации (например, реквизиты документа). Если же поле на форме связано с обычной переменной, объявленной через ключевое слово Перем, вызов УстановитьАтрибут() вернет ошибку «Неверное имя атрибута».

Решить эту проблему помогает недокументированная особенность передачи параметров в функции по ссылке. Создадим вспомогательную экспортную функцию в модуле формы:


Функция УстАтрибут(АтрибутФормы, НовоеЗначение) Экспорт
    АтрибутФормы = НовоеЗначение;
    Возврат "";
КонецФункции

Теперь мы можем изменять значение любой переменной формы, используя ту же функцию Шаблон(). Давайте посмотрим на пример реализации:


Процедура ЗаписатьЗначениеПоИмени(ИмяРеквизита, НовоеЗначение)
    // Создаем локальную переменную в текущем контексте
    ВременноеЗначение = НовоеЗначение; 
    
    // Выполняем динамическое присвоение через передачу по ссылке
    Шаблон("[УстАтрибут(" + ИмяРеквизита + ", ВременноеЗначение)]");
КонецПроцедуры

Этот хак базируется на том, что при вычислении шаблона платформа передает переменную формы мПоле в качестве первого параметра функции УстАтрибут() по ссылке. Функция присваивает ей новое значение, и переменная на форме мгновенно обновляется.

Метод 4. Профессиональное решение через внешнюю компоненту FormEx

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

С помощью FormEx мы можем перехватывать события интерактивного изменения данных и фокуса на системном уровне. В модуле формы достаточно описать предопределенную процедуру:


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

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

← На главную