Когда мы сталкиваемся с задачей программного изменения данных в 1С, часто возникает вопрос: как изменить реквизит формы? На первый взгляд, это кажется простой операцией, но здесь скрывается важный нюанс, который мы с вами сейчас подробно разберем. Существует принципиальная разница между реквизитом формы и реквизитом объекта информационной базы. Непонимание этой разницы часто приводит к ошибкам и неправильным решениям. Давайте вместе выясним, как правильно работать с каждым из этих типов реквизитов и какие инструменты 1С нам в этом помогут.
Чаще всего под "реквизитом формы" подразумевается реквизит, который отображается на форме, но на самом деле является реквизитом объекта информационной базы (например, справочника, документа и т.д.). Эти реквизиты хранятся в базе данных, и их изменение требует получения самого объекта, модификации его свойств и последующей записи. Рассмотрим подробнее, как это сделать.
Для изменения реквизита объекта, как правило, нам потребуется выполнить следующие шаги:
Выбрать() для справочников или запросом.ПолучитьОбъект(). Именно с объектом мы и будем работать.Записать().Посмотрим на пример кода, который демонстрирует массовое изменение реквизита КодКарты для элементов справочника ИнформационныеКарты:
&НаСервере
Процедура СделатьНаСервере()
Выборка = Справочники.ИнформационныеКарты.Выбрать();
Пока Выборка.Следующий() Цикл
Если НЕ Выборка.ЭтоГруппа И Выборка.КодКарты = "" Тогда
Карта = Выборка.ПолучитьОбъект();
Карта.КодКарты = Карта.Наименование;
Карта.Записать();
КонецЕсли;
КонецЦикла;
КонецПроцедуры
&НаКлиенте
Процедура Сделать(Команда)
СделатьНаСервере();
КонецПроцедуры
В этом примере мы видим, как сначала на сервере (&НаСервере) получаем выборку элементов справочника ИнформационныеКарты. Затем в цикле Пока Выборка.Следующий() Цикл проверяем, является ли элемент не группой и имеет ли пустой реквизит КодКарты. Если условия соблюдены, мы получаем объект (Карта = Выборка.ПолучитьОбъект()), присваиваем реквизиту КодКарты значение его Наименования и записываем объект (Карта.Записать()).
Аналогичную задачу можно решить с помощью запроса, что часто бывает более оптимально для больших объемов данных. Разберем по шагам пример использования запроса:
Запрос = Новый Запрос;
Запрос.Текст = "ВЫБРАТЬ
| ИнформационныеКарты.Ссылка КАК Ссылка,
| ИнформационныеКарты.Наименование КАК Наименование
|ИЗ
| Справочник.ИнформационныеКарты КАК ИнформационныеКарты
|ГДЕ
| НЕ ИнформационныеКарты.ЭтоГруппа
| И ИнформационныеКарты.КодКарты = """"";
Результат = Запрос.Выполнить();
Выборка = Результат.Выбрать();
Пока Выборка.Следующий() Цикл
Карта = Выборка.Ссылка.ПолучитьОбъект();
Карта.КодКарты = Выборка.Наименование;
Карта.ФлагКодаКарты = Истина; // Пример изменения дополнительного реквизита
Карта.Записать();
КонецЦикла;
Здесь мы сначала формируем запрос, который отбирает ссылки и наименования негрупповых элементов справочника ИнформационныеКарты с пустым реквизитом КодКарты. Затем выполняем запрос, получаем выборку и в цикле для каждой строки выборки получаем объект по ссылке (Выборка.Ссылка.ПолучитьОбъект()), изменяем его реквизиты (Карта.КодКарты, Карта.ФлагКодаКарты) и записываем объект.
Иногда, при попытке программно изменить и записать объект, мы сталкиваемся с тем, что наши изменения не сохраняются или сбрасываются. Причиной такого поведения часто являются типовые обработчики событий, такие как ПередЗаписью или ПриЗаписи, которые реализованы в модуле объекта конфигурации. Эти обработчики содержат логику, направленную на поддержание целостности данных, автоматическое заполнение или проверку реквизитов.
Проанализируем ситуацию на примере. Допустим, в модуле объекта Справочник.ИнформационныеКарты есть процедура ПередЗаписью, которая при определенных условиях (например, если ВидКарты равен Перечисления.ВидыИнформационныхКарт.Штриховая) очищает реквизит КодКарты:
Процедура ПередЗаписью(Отказ)
Если ОбменДанными.Загрузка Тогда
Возврат;
КонецЕсли;
Если ВидКарты = Перечисления.ВидыИнформационныхКарт.Штриховая Тогда
КодКарты = "";
КонецЕсли;
// ... другая логика
КонецПроцедуры
В этом случае, если наш объект имеет ВидКарты, соответствующий условию, наш программно установленный КодКарты будет сброшен перед записью. Как же быть?
Для обхода такой логики часто используют свойство ОбменДанными.Загрузка. Перед вызовом метода Записать() мы можем установить это свойство в ИСТИНА. Если в обработчике ПередЗаписью есть проверка на это свойство, то соответствующая логика будет пропущена:
Карта = Выборка.Ссылка.ПолучитьОбъект();
Карта.КодКарты = Выборка.Наименование;
Карта.ОбменДанными.Загрузка = ИСТИНА; // Устанавливаем режим загрузки
Карта.Записать();
Важно: Использование ОбменДанными.Загрузка = ИСТИНА должно быть осознанным. Мы ломаем типовые алгоритмы, и это может привести к записи некорректных данных, если логика в ПередЗаписью критически важна для поддержания целостности информационной базы. Прежде чем использовать этот подход, мы должны тщательно проанализировать код типовой конфигурации и убедиться, что это не приведет к нежелательным последствиям.
Теперь давайте рассмотрим ситуацию, когда нам действительно нужно изменить именно реквизит формы, а не реквизит объекта, который на ней отображается. Реквизиты формы существуют только в рамках конкретного экземпляра формы в оперативной памяти и не хранятся в базе данных. Они используются для отображения данных на экране, связи элементов формы с данными объекта или для других вспомогательных целей в рамках работы формы.
Программно добавлять, изменять и удалять реквизиты формы можно, но только те, которые были созданы программно. Нельзя удалить реквизиты, созданные в конфигураторе. Модификация формы (включая добавление/удаление реквизитов, команд и элементов) возможна только на сервере и "изнутри" формы, то есть из ее модуля.
Для программного изменения или добавления реквизитов формы используется метод ИзменитьРеквизиты(). Этому методу передается массив новых реквизитов, созданных с помощью объекта Новый РеквизитФормы(). Например, если мы хотим добавить новый реквизит формы ФлагКодаКарты:
&НаСервере
Процедура ЗаполнитьФлагиПоВидуКартыСервер()
// Пример изменения существующего реквизита формы
ФлагКодКарты = (Объект.ВидКарты = Перечисления.ВидыИнформационныхКарт.Магнитная)
ИЛИ (Объект.ВидКарты = Перечисления.ВидыИнформационныхКарт.Смешанная);
ФлагШтрихКод = (Объект.ВидКарты = Перечисления.ВидыИнформационныхКарт.Штриховая)
ИЛИ (Объект.ВидКарты = Перечисления.ВидыИнформационныхКарт.Смешанная);
// Пример добавления нового реквизита формы, если его нет
// Мы можем использовать ИзменитьРеквизиты для добавления
// или изменения свойств существующих программных реквизитов.
// Для реквизитов, созданных в конфигураторе, мы изменяем их значения напрямую.
// Допустим, мы хотим принудительно установить ФлагКодКарты в Истина
ФлагКодКарты = Истина; // Это прямой доступ к реквизиту формы
КонецПроцедуры
В данном примере ФлагКодКарты и ФлагШтрихКод, скорее всего, являются реквизитами формы. Мы можем напрямую присваивать им значения в серверных процедурах формы. Если же нам нужно добавить новый реквизит формы, мы должны создать его описание и передать методу ИзменитьРеквизиты():
&НаСервере
Процедура ДобавитьНовыйРеквизитФормы()
МассивНовыхРеквизитов = Новый Массив;
НовыйРеквизит = Новый РеквизитФормы("МойНовыйРеквизит", Новый ОписаниеТипов("Строка"), "Объект", "Мой новый реквизит на форме");
МассивНовыхРеквизитов.Добавить(НовыйРеквизит);
МассивУдаляемыхРеквизитов = Новый Массив; // Если нужно удалить ранее добавленный реквизит
ИзменитьРеквизиты(МассивНовыхРеквизитов, МассивУдаляемыхРеквизитов);
// После добавления, мы можем обратиться к нему
МойНовыйРеквизит = "Привет, я новый реквизит!";
КонецПроцедуры
При программном изменении формы необходимо управлять всей "троицей": реквизитами, командами и элементами. Например, чтобы разместить данные в форме, нужно создать реквизит, создать элемент управления и связать элемент с реквизитом.
В процессе работы с реквизитами и формами нам помогут следующие подходы и инструменты:
Записать() или в ПередЗаписью) и пошагово проследить выполнение, а также посмотреть текущие значения всех переменных и реквизитов.CTRL+F) по названию реквизита (например, КодКарты, ФлагКодаКарты) или по ключевым процедурам (ПередЗаписью, ПриСозданииНаСервере). Это позволит нам выяснить, где и как заполняется или изменяется реквизит, а также наличие типовых алгоритмов, которые могут влиять на его значение.Объект, то мы можем писать Объект.КодКарты. Методы и свойства формы имеют приоритет над методами и свойствами объекта в случае совпадения имен, поэтому для явного обращения к свойству объекта через основной реквизит формы, мы используем его имя (например, Объект.КодКарты).Таким образом, для программного изменения реквизита объекта (как в случае с КодКарты) мы используем прямой доступ к свойствам объекта и метод Записать(), возможно, с применением ОбменДанными.Загрузка = ИСТИНА. Для изменения именно реквизита формы мы работаем с методами формы на сервере, такими как ИзменитьРеквизиты(), либо напрямую присваиваем значения существующим реквизитам формы.