Почему переменные в управляемой форме 1С становятся "Неопределено" и как обеспечить их глобальную видимость?

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

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

Проблема контекста в управляемом приложении

Рассмотрим ситуацию, описанную автором темы. В модуле формы объявлены переменные:


перем ДокСсылка;
перем ПутьКФайлу;

Программист рассчитывает, что эти переменные будут играть роль "глобальных" внутри данного модуля. Однако в управляемом приложении 1С 8.3 существует жесткое разделение между клиентом и сервером. Это не просто разные программные слои, это часто разные физические процессы или даже разные компьютеры.

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

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

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

Разберем по шагам, как переделать код автора:

  1. Откройте форму в конфигураторе.
  2. Перейдите на закладку Реквизиты (в правой части редактора формы).
  3. Добавьте новый реквизит, например, ВыбранныйДокумент с типом ЛюбаяСсылка (или конкретным типом документа) и ПутьКФайлу с типом Строка.
  4. Теперь в коде вместо ДокСсылка обращайтесь к Объект.ВыбранныйДокумент (если реквизит добавлен в основной объект) или просто по имени ПутьКФайлу (если это реквизит самой формы).

Посмотрим на пример измененного кода:


&НаКлиенте
Процедура ПутьКДокументуНачалоВыбора(Элемент, ДанныеВыбора, СтандартнаяОбработка)
    // Вместо переменной используем реквизит формы
    СписокТипов = ПолучитьСписокТиповДокументов();
    ВвестиЗначение(ПутьКДокументуРеквизит, "Выберите документ", СписокТипов);
КонецПроцедуры

&НаКлиенте
Процедура ВыгрузитьДокумент(Команда)
    // Теперь значение доступно здесь, так как оно хранится в реквизите формы
    Если ЗначениеЗаполнено(ПутьКДокументуРеквизит) Тогда
        ВыполнитьДействиеНаСервере(ПутьКДокументуРеквизит);
    КонецЕсли;
КонецПроцедуры

Решение №2: Временное хранилище

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

Механизм работы следующий:

  1. На клиенте или сервере вы помещаете данные в хранилище с помощью функции ПоместитьВоВременноеХранилище(Данные, УникальныйИдентификаторФормы).
  2. Функция возвращает вам Адрес (строку).
  3. Этот Адрес вы сохраняете в реквизит формы (типа Строка).
  4. В любой другой процедуре (и на клиенте, и на сервере) вы можете обратиться по этому адресу и получить данные обратно.

Рассмотрим подробнее пример с файлом:


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

Решение №3: Параметры формы и ключевые параметры

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

Однако для внутренней логики работы одной формы, как в случае автора, лучше использовать именно реквизиты. Параметры формы доступны на сервере в процедуре ПриСозданииНаСервере, после чего их значения обычно переносятся в реквизиты для дальнейшей работы.

Важные нюансы работы с метаданными

Обратите внимание на ошибку в исходном сообщении автора: попытка вызвать ДокСсылка.Метаданные() на клиенте. В управляемом приложении работа с объектами метаданных на стороне клиента крайне ограничена. Выясним правило: если вам нужно узнать структуру документа, его реквизиты или тип — делайте это строго в процедурах &НаСервере или &НаСервереБезКонтекста.

Пример правильного получения метаданных:


&НаСервере
Процедура ПроверитьМетаданные(СсылкаНаДокумент)
    ИмяДокумента = СсылкаНаДокумент.Метаданные().Имя;
    Сообщить("Работаем с документом: " + ИмяДокумента);
КонецПроцедуры

Подведем итоги

Для обеспечения "глобальной" видимости объектов внутри управляемой формы 1С:

Соблюдение этих правил позволит вам избежать ошибок с неопределенными значениями и сделает ваш код стабильным и понятным.

← На главную