В процессе разработки в среде 1С:Предприятие 8.3 на управляемых формах мы часто сталкиваемся с необходимостью динамического управления интерфейсом. Одна из классических задач — скрыть определенное поле при выполнении некоторых условий и одновременно сбросить его значение (например, установить булево свойство в значение Ложь). Однако начинающие разработчики часто попадают в ментальную ловушку, пытаясь присвоить значение напрямую элементу формы. Давайте подробно разберем, почему возникает эта ошибка, как устроена архитектура управляемой формы и какие подходы к решению этой задачи считаются наиболее эффективными и профессиональными.
Рассмотрим ситуацию, с которой столкнулся автор вопроса на форуме. На форме программно создан реквизит и связанный с ним элемент. Разработчик пытается управлять видимостью и значением элемента на клиенте следующим образом:
&НаКлиенте
Процедура УправлениеЭлементом(НомерЭлемента)
ЭлементТест = ЭтаФорма.Элементы["Тест_" + НомерЭлемента];
ЭлементТест.Видимость = Ложь; // Успешно скрываем элемент
ЭлементТест = Ложь; // Значение не сбрасывается!
КонецПроцедуры
Выясним причину, почему видимость элемента меняется без проблем, а значение остается прежним. Проанализируем по шагам, что происходит в коде:
ЭлементТест = ЭтаФорма.Элементы["Тест_" + НомерЭлемента]; инициализирует локальную переменную ЭлементТест. В этой переменной теперь хранится ссылка на объект интерфейса (например, типа ПолеФормы).ЭлементТест.Видимость = Ложь; обращается к свойству самого визуального объекта на форме и успешно его скрывает.ЭлементТест = Ложь; совершает критическую логическую ошибку. Вместо изменения значения, привязанного к полю, мы просто перезаписываем значение локальной переменной ЭлементТест. Теперь вместо ссылки на элемент формы в ней хранится обычное булево значение Ложь. Сам элемент формы и данные, которые в нем отображались, остаются нетронутыми.Для понимания правильного подхода важно усвоить ключевое архитектурное правило управляемого приложения 1С. Платформа использует паттерн, близкий к концепции MVVM (Model-View-ViewModel), в котором данные формы и их визуальное представление строго изолированы друг от друга:
Булево, Число, Строка, ссылка на справочник и т.д.).Связующим звеном между ними выступает свойство элемента ПутьКДанным, в котором прописывается строковое имя реквизита формы. Таким образом, чтобы изменить значение на форме, мы должны обращаться не к элементу управления, а к реквизиту, с которым он связан.
Если имя реквизита формируется динамически (например, в зависимости от индекса, номера или префикса), мы не можем обратиться к нему через прямую точку, как мы обычно делаем с предопределенными реквизитами (например, Объект.ИмяРеквизита).
Для обращения к динамическому свойству контекста формы следует использовать оператор квадратных скобок. Давайте посмотрим на правильный вариант реализации задачи:
ИмяРеквизита = "Тест_" + НомерЭлемента;
// Скрываем элемент управления на форме
ЭтаФорма.Элементы[ИмяРеквизита].Видимость = Ложь;
// Устанавливаем значение в связанный реквизит формы
ЭтаФорма[ИмяРеквизита] = Ложь;
Этот способ является наиболее простым, лаконичным и отлично работает как на стороне клиента (&НаКлиенте), так и на сервере (&НаСервере).
Представим более сложную и универсальную ситуацию. У вас есть процедура, в которую передается сам элемент формы (например, в качестве отправителя события при нажатии кнопки или изменении значения), и вам нужно сбросить данные этого элемента, не зная заранее имени реквизита.
Для этого мы можем динамически прочитать свойство элемента ПутьКДанным. Разберем этот алгоритм по шагам:
&НаКлиенте
Процедура СброситьЗначениеЭлемента(ТекущийЭлемент)
// Получаем имя реквизита, к которому привязан элемент
ИмяРеквизита = ТекущийЭлемент.ПутьКДанным;
Если ЗначениеЗаполнено(ИмяРеквизита) Тогда
// Скрываем визуальную часть
ТекущийЭлемент.Видимость = Ложь;
// Сбрасываем значение в реквизите
ЭтаФорма[ИмяРеквизита] = Ложь;
КонецЕсли;
КонецПроцедуры
Важное примечание: Свойство элемента ПутьКДанным доступно на клиенте только для чтения, но этого абсолютно достаточно, чтобы получить имя реквизита в виде строки и перезаписать его значение в контексте ЭтаФорма.
При работе с динамически создаваемыми элементами разработчики часто совершают еще одну серьезную архитектурную ошибку — пытаются на лету удалять и создавать элементы и реквизиты формы в процессе работы пользователя через серверные вызовы.
Давайте проанализируем, почему этого делать категорически не рекомендуется:
ИзменитьРеквизиты() может выполняться только на сервере.Золотое правило разработки: Создавайте структуру реквизитов и элементов один раз при инициализации формы на сервере (в обработчике ПриСозданииНаСервере). Во время интерактивной работы пользователя на клиенте управляйте только видимостью элементов (Видимость = Ложь) и очищайте значения реквизитов, не изменяя саму структуру формы.
В рассматриваемом примере реквизит имел тип Булево, поэтому присвоение значения Ложь решило задачу. Однако на практике типы динамических полей могут быть самыми разными. Если вы попытаетесь записать Ложь в числовое поле или в поле ссылки на справочник, система выдаст ошибку несоответствия типов.
Давайте рассмотрим, как правильно и универсально очищать значения реквизитов в зависимости от их типа прямо на клиенте:
&НаКлиенте
Процедура ОчиститьДинамическийРеквизит(ИмяРеквизита)
ТекущееЗначение = ЭтаФорма[ИмяРеквизита];
ТипЗначения = ТипЗнч(ТекущееЗначение);
Если ТипЗначения = Тип("Булево") Тогда
ЭтаФорма[ИмяРеквизита] = Ложь;
ИначеЕсли ТипЗначения = Тип("Число") Тогда
ЭтаФорма[ИмяРеквизита] = 0;
ИначеЕсли ТипЗначения = Тип("Строка") Тогда
ЭтаФорма[ИмяРеквизита] = "";
ИначеЕсли ТипЗначения = Тип("Дата") Тогда
ЭтаФорма[ИмяРеквизита] = '00010101000000'; // Пустая дата
Иначе
// Для ссылочных типов (Справочники, Документы и т.д.)
// очистка на клиенте выполняется присвоением Неопределено
// или получением пустой ссылки.
ЭтаФорма[ИмяРеквизита] = ПредопределенноеЗначение("Справочник.Номенклатура.ПустаяСсылка");
// (Или укажите соответствующий тип ссылки)
КонецЕсли;
КонецПроцедуры
Используя данный подход, вы сможете писать надежный, отказоустойчивый и быстрый код управляемых форм 1С, соответствующий стандартам разработки фирмы "1С".