При разработке в 1С 7.7 часто возникает ситуация, когда необходимо взаимодействовать между различными формами, особенно когда одна форма открывается из другой. Распространенной задачей является присвоение значения реквизиту «родительской» формы из «дочерней» формы, открытой модально. Сложность заключается в том, что имя целевого реквизита может быть известно только в виде строки, и прямые методы присвоения значения по имени реквизита могут не работать так, как ожидается. В данной статье мы подробно разберем, как эффективно решить эту задачу, используя стандартные механизмы 1С 7.7, включая объект АтрибутФормы и правильное применение модальных форм.
Представим сценарий: у нас есть форма документа, на которой расположена кнопка. При нажатии на эту кнопку открывается форма обработки (назовем ее "дочерней" формой), где пользователь выбирает определенное значение. После выбора это значение должно быть возвращено и присвоено конкретному реквизиту на форме исходного документа (назовем ее "родительской" формой). Имя реквизита "родительской" формы, которому нужно присвоить значение, передается в "дочернюю" форму в виде строкового идентификатора.
Изначальная попытка динамического присвоения значения реквизиту формы по его имени обычно выглядит так:
Докум.Форма.УстановитьАтрибут(Реквизит, ЗначениеКотороеНадоПрисвоить);
где Докум — это контекст родительского документа, Форма — это объект формы родительского документа, а Реквизит — строковое имя целевого реквизита. Однако, как показывает практика, такой подход в 1С 7.7 не работает. Методы ПолучитьАтрибут() и УстановитьАтрибут() существуют для работы с атрибутами объектов (например, документов или справочников), но не для непосредственного динамического управления реквизитами объекта Форма. Объект Форма в 1С 7.7 обладает фиксированным набором методов и свойств, и динамическое изменение его реквизитов через строковые имена не является частью его стандартного функционала в такой прямой форме.
Следовательно, нам потребуется иной подход, использующий специально предназначенные для этого системные объекты 1С 7.7.
Прежде чем перейти к основному решению, давайте рассмотрим, как правильно организовать передачу данных между "родительской" и "дочерней" формой при модальном открытии. Модальное открытие означает, что "дочерняя" форма блокирует работу с "родительской" формой до тех пор, пока не будет закрыта. Это идеально подходит для нашего сценария, так как позволяет передать параметры при открытии и получить результат после закрытия.
В "родительской" форме (например, в модуле формы документа) при нажатии на кнопку мы будем вызывать процедуру, которая собирает необходимые параметры и открывает "дочернюю" форму модально. Ключевым моментом здесь является передача контекста "родительской" формы и строкового идентификатора реквизита, который мы хотим изменить.
// В модуле формы документа (родительская форма)
// Например, в процедуре, вызываемой при нажатии кнопки:
Процедура ВыборЗначенияИзОбработки(Команда, ИдентификаторРеквизита)
// Получаем контекст текущей формы документа
// Функция 'взятьКонтекст' - это вспомогательная функция,
// которая может просто возвращать текущий Контекст или выполнять дополнительные действия.
// Для простоты, допустим, она возвращает Контекст текущей формы.
Перем КонтекстФормыДокумента;
КонтекстФормыДокумента = Контекст;
// Создаем СписокЗначений для передачи параметров в дочернюю форму
СЗ_Параметры = СоздатьОбъект("СписокЗначений");
// Передаем контекст родительской формы.
// Это позволит дочерней форме обратиться к родительской.
СЗ_Параметры.ДобавитьЗначение(КонтекстФормыДокумента, "КонтекстРодительскойФормы");
// Передаем строковое имя реквизита, который нужно изменить
СЗ_Параметры.ДобавитьЗначение(ИдентификаторРеквизита, "ИмяЦелевогоРеквизита");
// Модально открываем форму обработки.
// После закрытия обработки, переменная СЗ_Параметры будет содержать возвращенное значение.
ОткрытьФормуМодально("Обработка.ВыборРеквизита", СЗ_Параметры);
// После закрытия дочерней формы, проверяем, было ли возвращено значение
// Возвращенное значение находится непосредственно в переменной СЗ_Параметры
// (если в дочерней форме мы присвоили его к Форма.Параметр)
Если ПустоеЗначение(СЗ_Параметры) = 0 Тогда
// Здесь мы получаем само значение, которое было выбрано в дочерней форме
ЗначениеВыбора = СЗ_Параметры;
// Теперь нам нужно присвоить это ЗначениеВыбора реквизиту на текущей форме
// с именем, переданным в ИдентификаторРеквизита.
// Используем объект АтрибутФормы, о котором поговорим ниже.
АФ = СоздатьОбъект("АтрибутФормы");
АФ.УстановитьАтрибут(Форма, ИдентификаторРеквизита);
АФ.Значение = ЗначениеВыбора;
// Важно обновить форму, чтобы изменения отобразились на экране
Форма.Обновить(1);
КонецЕсли;
КонецПроцедуры
Обратите внимание на то, как мы передаем КонтекстФормыДокумента. Это крайне важный шаг, так как именно через этот контекст дочерняя форма сможет получить ссылку на родительскую форму для последующего изменения ее реквизитов.
В "дочерней" форме (модуле формы обработки) мы будем получать переданные параметры и использовать их для своей работы. После того как пользователь сделает выбор, мы присвоим выбранное значение свойству Форма.Параметр, чтобы оно было возвращено в "родительскую" форму.
// В модуле формы обработки (дочерняя форма)
Перем КонтекстРодительскойФормы; // Переменная для хранения контекста родительской формы
Перем ИмяЦелевогоРеквизита; // Переменная для хранения имени реквизита родительской формы
Процедура ПриОткрытии()
// Получаем переданные параметры при открытии формы
// Форма.Параметр в данном случае является объектом СписокЗначений, переданным из родительской формы.
Если ТипЗначения(Форма.Параметр) = 8 Тогда // 8 - это тип значения "СписокЗначений"
КонтекстРодительскойФормы = Форма.Параметр.Получить("КонтекстРодительскойФормы");
ИмяЦелевогоРеквизита = Форма.Параметр.Получить("ИмяЦелевогоРеквизита");
Иначе
// Обработка случая, если параметры переданы некорректно или их нет
Сообщить("Ошибка: Не переданы необходимые параметры для работы обработки.");
СтатусВозврата(0); // Закрываем форму без возврата значения
Возврат;
КонецЕсли;
// Здесь может быть код для инициализации элементов формы обработки,
// например, загрузка данных для выбора, основываясь на ИмяЦелевогоРеквизита или других параметрах.
// ...
КонецПроцедуры
// Например, в процедуре, вызываемой при выборе значения пользователем:
Процедура ВыбратьЗначение(ЗначениеВыбора)
// Присваиваем выбранное значение свойству Форма.Параметр.
// Это значение будет возвращено в родительскую форму после закрытия модальной формы.
Форма.Параметр = ЗначениеВыбора;
// Закрываем текущую (дочернюю) форму
СтатусВозврата(1); // 1 - успешно, 0 - отмена
Закрыть(0); // Закрываем форму
КонецПроцедуры
Теперь, когда мы понимаем механизм передачи контекста и возврата значений, мы можем перейти к ключевому элементу решения — динамическому присвоению значения реквизиту.
Для динамического присвоения значения реквизиту формы по его строковому имени в 1С 7.7 существует специальный системный объект — АтрибутФормы. Этот объект был создан именно для таких задач, позволяя программно управлять элементами формы, когда их имена известны только во время выполнения.
Первым шагом является создание экземпляра объекта АтрибутФормы:
АФ = СоздатьОбъект("АтрибутФормы");
Мы создаем временный объект АФ, который будет служить инструментом для взаимодействия с реквизитом формы.
После создания объекта АтрибутФормы необходимо связать его с конкретным реквизитом определенной формы. Для этого используется метод УстановитьАтрибут() объекта АФ:
АФ.УстановитьАтрибут(ОбъектФормы, ИмяРеквизитаСтрокой);
Разберем параметры:
ОбъектФормы: Это объект формы, реквизит которой мы хотим изменить. В нашем случае, это будет контекст родительской формы, полученный при открытии дочерней формы. Например, КонтекстРодительскойФормы.Форма. Если мы хотим изменить реквизит текущей дочерней формы (что менее вероятно в данном сценарии, но возможно), то используем просто Форма.ИмяРеквизитаСтрокой: Это строковое имя реквизита, который нужно изменить. Это та самая переменная ИмяЦелевогоРеквизита, которую мы передали из родительской формы.После того как объект АтрибутФормы привязан к нужному реквизиту, мы можем присвоить ему значение через свойство Значение объекта АФ:
АФ.Значение = НовоеЗначение;
Здесь НовоеЗначение — это то значение, которое мы хотим установить в реквизит формы. Это может быть ссылка на элемент справочника, строка, число, дата и т.д., в зависимости от типа реквизита.
Давайте интегрируем эти шаги в процедуру выбора значения в нашей "дочерней" форме, если бы мы хотели изменить реквизит родительской формы непосредственно из дочерней формы (хотя более корректно возвращать значение и присваивать его в родительской):
// В модуле формы обработки (дочерняя форма)
// Предполагаем, что КонтекстРодительскойФормы и ИмяЦелевогоРеквизита
// уже получены в ПриОткрытии()
Процедура ВыбратьЗначение(ЗначениеВыбора)
// 1. Проверяем, что у нас есть контекст родительской формы
Если ТипЗначения(КонтекстРодительскойФормы) = 0 Тогда // Пустое значение
Сообщить("Ошибка: Контекст родительской формы не получен.");
СтатусВозврата(0);
Закрыть(0);
Возврат;
КонецЕсли;
// 2. Создаем объект АтрибутФормы
АФ = СоздатьОбъект("АтрибутФормы");
// 3. Привязываем АФ к реквизиту родительской формы
// КонтекстРодительскойФормы содержит ссылку на объект документа/справочника,
// поэтому для доступа к ЕГО ФОРМЕ используем КонтекстРодительскойФормы.Форма
АФ.УстановитьАтрибут(КонтекстРодительскойФормы.Форма, ИмяЦелевогоРеквизита);
// 4. Присваиваем выбранное значение
АФ.Значение = ЗначениеВыбора;
// 5. После присвоения значения, важно обновить родительскую форму,
// чтобы изменения отобразились на экране.
КонтекстРодительскойФормы.Форма.Обновить(1); // Параметр 1 принуждает к обновлению
// 6. Закрываем текущую (дочернюю) форму, сигнализируя об успешном завершении
СтатусВозврата(1);
Закрыть(0);
КонецПроцедуры
Как мы видим, объект АтрибутФормы предоставляет элегантное и прямое решение для динамического управления реквизитами формы в 1С 7.7. Он позволяет преодолеть ограничение на прямое обращение к реквизитам формы по строковому имени и делает код более гибким и масштабируемым.
Форма.Обновить(1)После того как вы программно изменили значение реквизита формы, особенно если это происходит не в текущей, а в другой (родительской) форме, крайне важно обновить эту форму, чтобы пользователь увидел изменения на экране. Если не вызвать метод Обновить(), форма может продолжать отображать старое значение, несмотря на то, что в памяти оно уже изменено.
Для обновления формы используйте метод Обновить(1):
КонтекстРодительскойФормы.Форма.Обновить(1);
Параметр 1 в данном случае означает принудительное обновление всех элементов формы, что гарантирует отображение актуальных данных. Если вы изменили реквизит текущей формы, вызовите:
Форма.Обновить(1);
Вызов Форма.Обновить(1) обеспечивает синхронизацию визуального представления формы с ее внутренним состоянием, что является критически важным для корректной работы пользовательского интерфейса.
В некоторых случаях, когда речь идет не о произвольном реквизите формы, а о реквизите самого объекта данных, привязанного к форме (например, реквизите документа, элемента справочника), задача может быть решена проще, без использования АтрибутФормы.
Предположим, что Докум (полученный контекст родительской формы) является ссылкой на объект документа, и мы хотим изменить один из его реквизитов, который также отображается на форме (например, реквизит "Контрагент"). В этом случае можно использовать метод УстановитьАтрибут() самого объекта:
// В дочерней форме, после получения КонтекстРодительскойФормы
// Допустим, мы хотим присвоить Контрагента в родительском документе
// и ИмяЦелевогоРеквизита пришло как "Контрагент"
Если ТипЗначения(КонтекстРодительскойФормы) = 11 Тогда // 11 - тип "Документ"
КонтекстРодительскойФормы.УстановитьАтрибут(ИмяЦелевогоРеквизита, ЗначениеВыбора);
// ИЛИ напрямую, если имя реквизита известно:
// КонтекстРодительскойФормы.Контрагент = ЗначениеВыбора;
// После изменения реквизита объекта, также необходимо обновить форму
КонтекстРодительскойФормы.Форма.Обновить(1);
КонецЕсли;
Ключевое отличие: Метод УстановитьАтрибут(), вызываемый непосредственно на объекте Документ, изменяет данные самого документа в базе данных (или в его буферной копии), а не только визуальное представление на форме. Однако, для того чтобы эти изменения отобразились на форме, все равно потребуется вызов КонтекстРодительскойФормы.Форма.Обновить(1).
Используйте этот подход, если Реквизит, который вы хотите изменить, является непосредственным реквизитом объекта, с которым работает форма (например, реквизитом документа или справочника), а не просто независимым элементом управления, добавленным на форму.
Существует также более продвинутый и гибкий подход, известный как "лайфхак с шаблоном" (или "метод шаблона"), который позволяет динамически формировать и выполнять фрагменты кода 1С 7.7. Этот метод может быть использован для выполнения произвольных операций с элементами формы по их строковым именам, включая присвоение значений.
Суть метода: Он основан на том, что можно создать текстовую строку, содержащую код 1С, и затем выполнить ее. Например, если у нас есть строковое имя реквизита "МойРеквизит" и значение "НовоеЗначение", мы можем сформировать строку типа "Форма.МойРеквизит = ""НовоеЗначение"";" и затем выполнить ее с помощью специальных функций. Этот подход требует более глубокого понимания динамического выполнения кода и может быть сложнее в реализации и отладке.
Когда использовать: Метод шаблона полезен в ситуациях, когда необходимо выполнить не просто присвоение значения, а более сложные операции, где АтрибутФормы может быть недостаточно гибким (например, вызов методов элементов управления формы по имени, динамическое изменение свойств элементов и т.д.). Однако для простой задачи присвоения значения реквизиту формы объект АтрибутФормы является более простым, безопасным и рекомендованным решением.
Помните, что использование шаблонов и динамического выполнения кода может привести к снижению читаемости и усложнению поддержки кода, поэтому применять его следует осознанно и только в тех случаях, когда другие, более прямые методы не подходят.
Объект.УстановитьАтрибут() или АтрибутФормы).АтрибутФормы может вызвать ошибку. Предусматривайте механизмы обработки таких ситуаций (например, с использованием Попытка...Исключение, если это применимо, или предварительной проверки существования реквизита, хотя в 1С 7.7 это сделать сложнее).Мы рассмотрели исчерпывающий подход к динамическому присвоению значения реквизиту формы 1С 7.7 по его строковому идентификатору. Основное и наиболее эффективное решение заключается в использовании системного объекта АтрибутФормы. Этот объект позволяет точно указать целевую форму и имя реквизита в виде строки, а затем присвоить ему необходимое значение. Не забывайте о важности обновления формы после внесения изменений с помощью Форма.Обновить(1) для корректного отображения данных пользователю.
Помните, что понимание механизма передачи параметров через модальные формы является фундаментальным для построения гибких и интерактивных интерфейсов в 1С 7.7. В ситуациях, когда вы работаете непосредственно с реквизитами объекта, можно использовать более прямой метод Объект.УстановитьАтрибут(). А для самых сложных и нетривиальных задач всегда есть возможность прибегнуть к "лайфхаку с шаблоном", хоть он и требует более глубоких знаний и аккуратности.
Применяя эти методы, вы сможете создавать более мощные и пользовательские решения, эффективно управляя взаимодействием между различными формами вашей конфигурации 1С 7.7.