При разработке интерфейсов на управляемых формах 1С:Предприятия разработчики часто сталкиваются с задачей динамического управления видимостью элементов в зависимости от введенных пользователем данных. Например, при выборе определенной номенклатуры в табличной части нам может потребоваться скрыть или показать колонку со спецификацией, размером или дополнительными реквизитами. Однако при реализации этой логики "в лоб" возникает неприятная проблема: в момент выбора значения в ячейке соседняя колонка скрывается, но само выбранное значение в текущей строке бесследно исчезает, возвращаясь к пустому или предыдущему значению.
В этой статье мы подробно разберем физику этого процесса на уровне платформы 1С, выясним истинные причины такого поведения и рассмотрим четыре надежных практических способа решения этой проблемы с примерами кода.
Для того чтобы понять, почему зачищается значение в строке, проанализируем жизненный цикл редактирования ячейки в управляемой форме. Этот процесс состоит из нескольких последовательных фаз:
ТекущиеДанные).ОбработкаВыбора или ПриИзменении.Видимость любой колонки этой таблицы (например, Элементы.ТоварыСпецификация.Видимость = Ложь;), платформа 1С вынуждена выполнить ререндеринг (полную перерисовку) всей структуры таблицы на клиенте. Смена видимости колонки кардинально меняет геометрическую сетку таблицы, разметку и ширину других колонок. Чтобы отобразить эти изменения, платформа мгновенно уничтожает текущее визуальное дерево таблицы на клиенте и строит его заново.Теперь, когда мы проанализировали ситуацию и понимаем природу этой проблемы, рассмотрим по шагам методы её обхода.
Основная идея этого способа заключается в том, чтобы искусственно разделить во времени два несовместимых процесса: фиксацию введенных данных в ячейке таблицы и изменение структуры этой таблицы на клиенте. Мы дадим платформе завершить запись значения, а уже затем перерисуем интерфейс.
Рассмотрим, как это реализовать на практике. Вместо мгновенного изменения видимости в обработчике события мы подключим однократный обработчик ожидания с минимальной задержкой (например, 0.1 секунды).
Посмотрим на пример кода:
&НаКлиенте
Процедура ТоварыНоменклатураПриИзменении(Элемент)
// Платформа выполнит запись значения в реквизит строки.
// Параллельно мы запускаем однократный таймер.
ПараметрыПроцедуры = Новый Структура("ТекущаяСтрока", Элементы.Товары.ТекущаяСтрока);
// Подключаем обработчик ожидания с минимальной задержкой.
// Третий параметр "Истина" указывает, что вызов будет однократным.
ПодключитьОбработчикОжидания("Подключаемый_УправлениеВидимостьюКолонок", 0.1, Истина);
КонецПроцедуры
&НаКлиенте
Процедура Подключаемый_УправлениеВидимостьюКолонок()
// Данный метод сработает через 0.1 сек, когда сеанс редактирования уже завершен,
// и данные успешно зафиксированы в реквизите строки ТЧ.
ТекущиеДанные = Элементы.Товары.ТекущиеДанные;
Если ТекущиеДанные <> Неопределено Тогда
// Проверяем условие на основе уже сохраненных данных
Если ТекущиеДанные.ТипНоменклатуры = ПредопределенноеЗначение("Перечисление.ТипыНоменклатуры.Услуга") Тогда
Элементы.ТоварыСпецификация.Видимость = Ложь;
Иначе
Элементы.ТоварыСпецификация.Видимость = Истина;
КонецЕсли;
КонецЕсли;
КонецПроцедуры
Этот способ является наиболее популярным среди разработчиков 1С, так как он гарантирует 100% сохранность введенных данных и не ломает стандартное интерактивное поведение платформы.
Если бизнес-требования к интерфейсу допускают, что колонка может оставаться на экране, но при этом должна быть заблокирована от изменений, мы рекомендуем заменить свойство Видимость на свойства Доступность или ТолькоПросмотр.
Изменение доступности колонки или конкретной ячейки не приводит к глобальному изменению геометрической сетки таблицы на клиенте. Платформа просто меняет визуальный стиль отображения ячейки и блокирует ввод, не уничтожая буферы ввода в соседних колонках. Это позволяет избежать аварийного закрытия сеанса редактирования.
Проанализируем пример кода:
&НаКлиенте
Процедура ТоварыНоменклатураПриИзменении(Элемент)
ТекущиеДанные = Элементы.Товары.ТекущиеДанные;
Если ТекущиеДанные <> Неопределено Тогда
// Изменение свойства "ТолькоПросмотр" элемента формы не вызывает перерисовку таблицы.
// Данные в текущей редактируемой ячейке гарантированно сохранятся.
Если ТекущиеДанные.ТипНоменклатуры = ПредопределенноеЗначение("Перечисление.ТипыНоменклатуры.Услуга") Тогда
Элементы.ТоварыСпецификация.ТолькоПросмотр = Истина;
Иначе
Элементы.ТоварыСпецификация.ТолькоПросмотр = Ложь;
КонецЕсли;
КонецЕсли;
КонецПроцедуры
Важное примечание: Свойство ТолькоПросмотр или Доступность, установленное для колонки в целом на клиенте, заблокирует всю колонку во всех строках таблицы. Если вам необходимо блокировать ввод выборочно для конкретных строк, используйте механизм условного оформления, который мы разберем далее.
Использование механизма Условного оформления управляемой формы — это золотой стандарт разработки в концепции 1С. Вместо написания императивного кода скрытия и блокировки элементов в событиях ячеек, мы можем один раз задекларировать правила поведения элементов формы на сервере.
Условное оформление работает оптимизированно "на лету" на уровне платформы. Платформа сама отслеживает изменения в строках и блокирует или визуально выделяет нужные ячейки без риска прерывания ввода пользователя.
Рассмотрим пример программной настройки условного оформления при создании формы на сервере:
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
НастроитьБлокировкуСпецификации();
КонецПроцедуры
&НаСервере
Процедура НастроитьБлокировкуСпецификации()
// Добавляем новое правило условного оформления
ЭлементОформления = УсловноеОформление.Элементы.Добавить();
// 1. Устанавливаем оформление: блокируем ячейку для ввода
ЭлементОформления.Оформление.УстановитьЗначениеПараметра("ТолькоПросмотр", Истина);
// Опционально: визуально выделим заблокированную ячейку серым цветом
ЭлементОформления.Оформление.УстановитьЗначениеПараметра("ЦветФона", ЦветаСтиля.ФормаЦветФона);
// 2. Задаем условие: блокировка срабатывает, если ТипНоменклатуры равен "Услуга"
ЭлементОтбора = ЭлементОформления.Отбор.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
ЭлементОтбора.ЛевоеЗначение = Новый ПолеКомпоновкиДанных("Объект.Товары.ТипНоменклатуры");
ЭлементОтбора.ВидСравнения = ВидСравненияКомпоновкиДанных.Равно;
ЭлементОтбора.ПравоеЗначение = ПредопределенноеЗначение("Перечисление.ТипыНоменклатуры.Услуга");
// 3. Указываем оформляемое поле - колонку "ТоварыСпецификация"
ОформляемоеПоле = ЭлементОформления.Поля.Элементы.Добавить();
ОформляемоеПоле.Поле = Новый ПолеКомпоновкиДанных("ТоварыСпецификация");
КонецПроцедуры
Этот способ идеален, так как он не требует написания сложного кода на клиенте и полностью поддерживается платформой на уровне встроенных оптимизаций отображения данных.
Если вам критически важно полностью скрыть колонку (сделать видимость Ложь) в момент интерактивного выбора и без использования обработчиков ожидания, вы можете перехватить инициативу у платформы в обработчике события ОбработкаВыбора.
Для этого мы вручную запишем выбранное пользователем значение непосредственно в текущую строку данных и отменим стандартную обработку события платформы с помощью параметра СтандартнаяОбработка = Ложь. Поскольку значение будет гарантированно записано в реквизит формы до того, как сработает изменение видимости колонки, ререндеринг таблицы уже не сможет стереть наши данные.
Разберем данный подход по шагам на примере кода:
&НаКлиенте
Процедура ТоварыНоменклатураОбработкаВыбора(Элемент, ВыбранноеЗначение, СтандартнаяОбработка)
// Отменяем штатный механизм фиксации выбора платформы
СтандартнаяОбработка = Ложь;
ТекущиеДанные = Элементы.Товары.ТекущиеДанные;
Если ТекущиеДанные <> Неопределено Тогда
// Вручную записываем выбранное значение напрямую в реквизит строки
ТекущиеДанные.Номенклатура = ВыбранноеЗначение;
// Проводим сопутствующие расчеты, которые обычно делает платформа (например, заполнение цен)
// ОбработатьВыборНоменклатурыНаСервере(ТекущиеДанные);
// Теперь, когда данные сохранены в коллекции формы, мы можем безопасно менять видимость
Если ВыбранноеЗначение.ТипНоменклатуры = ПредопределенноеЗначение("Перечисление.ТипыНоменклатуры.Услуга") Тогда
Элементы.ТоварыСпецификация.Видимость = Ложь;
Иначе
Элементы.ТоварыСпецификация.Видимость = Истина;
КонецЕсли;
КонецЕсли;
КонецПроцедуры
Обратите внимание: При использовании этого метода вы берете на себя полную ответственность за сопутствующие алгоритмы (очистка зависимых полей, пересчет сумм, вызов серверных процедур заполнения по умолчанию), которые обычно автоматически срабатывают при стандартной обработке выбора.
Проанализируем все четыре решения, чтобы вам было проще сделать выбор для вашей конкретной задачи:
Используя предложенные методики, вы сможете создавать отзывчивые, динамические и отказоустойчивые интерфейсы в управляемом приложении 1С:Предприятия, избегая досадных ошибок с потерей данных пользователей при заполнении табличных частей.