Как программно изменить реквизит формы в 1С:Предприятие?

Программист 1С v8.3 (Управляемые формы) 1С:Розница Управленческий учет Торговля и дистрибуция
← К списку

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

Изменение реквизитов объекта информационной базы через программный код

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

Для изменения реквизита объекта, как правило, нам потребуется выполнить следующие шаги:

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

Посмотрим на пример кода, который демонстрирует массовое изменение реквизита КодКарты для элементов справочника ИнформационныеКарты:


&НаСервере
Процедура СделатьНаСервере()
    Выборка = Справочники.ИнформационныеКарты.Выбрать();
    Пока Выборка.Следующий() Цикл
        Если НЕ Выборка.ЭтоГруппа И Выборка.КодКарты = "" Тогда
            Карта = Выборка.ПолучитьОбъект();
            Карта.КодКарты = Карта.Наименование;
            Карта.Записать();
        КонецЕсли;
    КонецЦикла;
КонецПроцедуры

&НаКлиенте
Процедура Сделать(Команда)
    СделатьНаСервере();
КонецПроцедуры

В этом примере мы видим, как сначала на сервере (&НаСервере) получаем выборку элементов справочника ИнформационныеКарты. Затем в цикле Пока Выборка.Следующий() Цикл проверяем, является ли элемент не группой и имеет ли пустой реквизит КодКарты. Если условия соблюдены, мы получаем объект (Карта = Выборка.ПолучитьОбъект()), присваиваем реквизиту КодКарты значение его Наименования и записываем объект (Карта.Записать()).

Аналогичную задачу можно решить с помощью запроса, что часто бывает более оптимально для больших объемов данных. Разберем по шагам пример использования запроса:


Запрос = Новый Запрос;
Запрос.Текст = "ВЫБРАТЬ
|    ИнформационныеКарты.Ссылка КАК Ссылка,
|    ИнформационныеКарты.Наименование КАК Наименование
|ИЗ
|    Справочник.ИнформационныеКарты КАК ИнформационныеКарты
|ГДЕ
|    НЕ ИнформационныеКарты.ЭтоГруппа
|    И ИнформационныеКарты.КодКарты = """"";

Результат = Запрос.Выполнить();
Выборка = Результат.Выбрать();

Пока Выборка.Следующий() Цикл
    Карта = Выборка.Ссылка.ПолучитьОбъект();
    Карта.КодКарты = Выборка.Наименование;
    Карта.ФлагКодаКарты = Истина; // Пример изменения дополнительного реквизита
    Карта.Записать();
КонецЦикла;

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

Обход типовых обработчиков при записи объекта

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

Проанализируем ситуацию на примере. Допустим, в модуле объекта Справочник.ИнформационныеКарты есть процедура ПередЗаписью, которая при определенных условиях (например, если ВидКарты равен Перечисления.ВидыИнформационныхКарт.Штриховая) очищает реквизит КодКарты:


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

В этом случае, если наш объект имеет ВидКарты, соответствующий условию, наш программно установленный КодКарты будет сброшен перед записью. Как же быть?

Для обхода такой логики часто используют свойство ОбменДанными.Загрузка. Перед вызовом метода Записать() мы можем установить это свойство в ИСТИНА. Если в обработчике ПередЗаписью есть проверка на это свойство, то соответствующая логика будет пропущена:


Карта = Выборка.Ссылка.ПолучитьОбъект();
Карта.КодКарты = Выборка.Наименование;
Карта.ОбменДанными.Загрузка = ИСТИНА; // Устанавливаем режим загрузки
Карта.Записать();

Важно: Использование ОбменДанными.Загрузка = ИСТИНА должно быть осознанным. Мы ломаем типовые алгоритмы, и это может привести к записи некорректных данных, если логика в ПередЗаписью критически важна для поддержания целостности информационной базы. Прежде чем использовать этот подход, мы должны тщательно проанализировать код типовой конфигурации и убедиться, что это не приведет к нежелательным последствиям.

Программное изменение реквизитов формы (не объекта)

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

Программно добавлять, изменять и удалять реквизиты формы можно, но только те, которые были созданы программно. Нельзя удалить реквизиты, созданные в конфигураторе. Модификация формы (включая добавление/удаление реквизитов, команд и элементов) возможна только на сервере и "изнутри" формы, то есть из ее модуля.

Для программного изменения или добавления реквизитов формы используется метод ИзменитьРеквизиты(). Этому методу передается массив новых реквизитов, созданных с помощью объекта Новый РеквизитФормы(). Например, если мы хотим добавить новый реквизит формы ФлагКодаКарты:


&НаСервере
Процедура ЗаполнитьФлагиПоВидуКартыСервер()
    // Пример изменения существующего реквизита формы
    ФлагКодКарты =      (Объект.ВидКарты = Перечисления.ВидыИнформационныхКарт.Магнитная)
                    ИЛИ (Объект.ВидКарты = Перечисления.ВидыИнформационныхКарт.Смешанная);

    ФлагШтрихКод =      (Объект.ВидКарты = Перечисления.ВидыИнформационныхКарт.Штриховая)
                    ИЛИ (Объект.ВидКарты = Перечисления.ВидыИнформационныхКарт.Смешанная);

    // Пример добавления нового реквизита формы, если его нет
    // Мы можем использовать ИзменитьРеквизиты для добавления
    // или изменения свойств существующих программных реквизитов.
    // Для реквизитов, созданных в конфигураторе, мы изменяем их значения напрямую.
    
    // Допустим, мы хотим принудительно установить ФлагКодКарты в Истина
    ФлагКодКарты = Истина; // Это прямой доступ к реквизиту формы
КонецПроцедуры

В данном примере ФлагКодКарты и ФлагШтрихКод, скорее всего, являются реквизитами формы. Мы можем напрямую присваивать им значения в серверных процедурах формы. Если же нам нужно добавить новый реквизит формы, мы должны создать его описание и передать методу ИзменитьРеквизиты():


&НаСервере
Процедура ДобавитьНовыйРеквизитФормы()
    МассивНовыхРеквизитов = Новый Массив;
    НовыйРеквизит = Новый РеквизитФормы("МойНовыйРеквизит", Новый ОписаниеТипов("Строка"), "Объект", "Мой новый реквизит на форме");
    МассивНовыхРеквизитов.Добавить(НовыйРеквизит);
    
    МассивУдаляемыхРеквизитов = Новый Массив; // Если нужно удалить ранее добавленный реквизит
    
    ИзменитьРеквизиты(МассивНовыхРеквизитов, МассивУдаляемыхРеквизитов);
    
    // После добавления, мы можем обратиться к нему
    МойНовыйРеквизит = "Привет, я новый реквизит!";
КонецПроцедуры

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

Дополнительные советы и инструменты

В процессе работы с реквизитами и формами нам помогут следующие подходы и инструменты:

  1. Использование отладчика: Если мы не понимаем, почему реквизит не меняется или меняется не так, как ожидается, отладчик – наш лучший друг. Мы можем поставить точку останова в интересующем нас месте кода (например, перед Записать() или в ПередЗаписью) и пошагово проследить выполнение, а также посмотреть текущие значения всех переменных и реквизитов.
  2. Анализ кода модуля объекта/формы: Откройте дерево конфигурации, найдите нужный справочник или документ, перейдите в его модуль объекта или модуль формы. Используйте поиск (CTRL+F) по названию реквизита (например, КодКарты, ФлагКодаКарты) или по ключевым процедурам (ПередЗаписью, ПриСозданииНаСервере). Это позволит нам выяснить, где и как заполняется или изменяется реквизит, а также наличие типовых алгоритмов, которые могут влиять на его значение.
  3. Контекст формы и основной реквизит: Если форма имеет основной реквизит (например, типа "Объект"), то в модуле формы мы можем напрямую обращаться к свойствам этого объекта. Например, если основной реквизит называется Объект, то мы можем писать Объект.КодКарты. Методы и свойства формы имеют приоритет над методами и свойствами объекта в случае совпадения имен, поэтому для явного обращения к свойству объекта через основной реквизит формы, мы используем его имя (например, Объект.КодКарты).
  4. Внешние обработки для работы с данными: Существуют полезные инструменты, такие как внешние обработки типа "Редактировать Объект БД" или "Групповое изменение реквизитов", которые позволяют интерактивно или программно изменять множество элементов или документов, в том числе обходя некоторые типовые проверки.

Таким образом, для программного изменения реквизита объекта (как в случае с КодКарты) мы используем прямой доступ к свойствам объекта и метод Записать(), возможно, с применением ОбменДанными.Загрузка = ИСТИНА. Для изменения именно реквизита формы мы работаем с методами формы на сервере, такими как ИзменитьРеквизиты(), либо напрямую присваиваем значения существующим реквизитам формы.

← К списку