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