Разработчики, продолжающие поддерживать и развивать системы на платформе 1С:Предприятие 7.7, часто сталкиваются с «фантомными» багами, которые кажутся необъяснимыми. Одной из таких проблем является некорректная работа метода ИерархическийСписок(). В определенных условиях после программного включения иерархии дерево групп «схлопывается», часть элементов исчезает, а позиционирование на текущем объекте сбивается.
В этой статье мы подробно проанализируем ситуацию, выясним истинные причины такого поведения платформы и разберем наиболее надежные способы решения проблемы с использованием возможностей внешней компоненты FormEX.
Проблема проявляется в тех случаях, когда в форме списка справочника присутствует текстовая колонка, в формуле которой вызывается пользовательская функция. Если эта функция выполняет какие-либо операции, отличные от простейшего возврата строки (например, создает объекты СписокЗначений, ТаблицаЗначений или содержит циклы), механизм отрисовки 1С начинает конфликтовать с внутренним индексом дерева элементов.
Рассмотрим пример функции, которая часто используется для раскраски строк, но при этом провоцирует сбой иерархии:
Функция глРаскраска(АктивныйЦвет = "Серый") Экспорт
// Даже создание пустого объекта в момент отрисовки строки может вызвать сбой
НаборИменЦветов = СоздатьОбъект("СписокЗначений");
НаборИменЦветов.ДобавитьЗначение("BRUSH_S");
НаборИменЦветов.ДобавитьЗначение("FONT");
// Любой цикл, увеличивающий время выполнения функции
Для н = 1 По 10 Цикл
// Какая-то логика
КонецЦикла;
Возврат "";
КонецФункции
Если при наличии такой колонки вызвать метод ИерархическийСписок(1, 1), платформа может «потерять» уровни вложенности. Например, вместо цепочки Группа 1 -> Группа 2 -> Элемент вы увидите только Группа 1, а остальные элементы просто исчезнут из видимости до ручного обновления формы.
Разберем внутренние механизмы платформы. Визуальный список в 1С 7.7 (так называемый VList) работает в виртуальном режиме. Это означает, что данные запрашиваются только для тех строк, которые видны на экране. Когда мы программно меняем режим иерархии, 1С инициирует полную перестройку дерева видимых элементов.
Если в этот критический момент отрисовки вызывается тяжелая функция из текстовой колонки, происходит следующее:
WM_PAINT).Интересно, что при нажатии на стандартную кнопку иерархии в панели инструментов «Действия» проблема не возникает. Это наталкивает на мысль, что стандартная кнопка использует другой механизм, нежели метод встроенного языка ИерархическийСписок().
Наиболее эффективным решением является эмуляция нажатия системной кнопки иерархии. Для этого нам понадобится объект Окна из состава FormEX. Мы будем использовать метод ПослатьКоманду(), который отправляет сообщение WM_COMMAND главному окну приложения.
Идентификатор команды (Command ID) для переключения иерархического списка в 1С 7.7 — 32866. Рассмотрим, как это реализовать в коде:
Процедура ПрограммноеВключениеИерархии()
Попытка
СервисОкон = СоздатьОбъект("Окна");
// 32866 - это системный ID команды "Иерархический список"
СервисОкон.ПослатьКоманду(32866, 0);
Исключение
// Если FormEX не загружен, используем штатный метод
ИерархическийСписок(1, 1);
КонецПопытки;
КонецПроцедуры
Преимущества этого подхода:
Если основной причиной использования текстовой колонки была раскраска строк, проанализируем возможность перехода на современный механизм FormEX, который не требует наличия лишних колонок в форме. В новых версиях компоненты (начиная с 2.0.x) реализован «План раскраски», который работает через перехват событий отрисовки на уровне WinAPI.
Для активации этого режима выполним следующие шаги в ПриОткрытии() формы или в глобальном модуле:
Сервис = СоздатьОбъект("Сервис");
Сервис.ВключитьРаскраскуТаблиц(1);
Сервис.ИспользоватьПланРаскраски(1);
После этого мы можем реализовать раскраску в процедуре ПослеОтрисовкиЭлемента(). Поскольку текстовая колонка с формулой будет удалена, нагрузка на отрисовку снизится, и штатный метод ИерархическийСписок() станет работать значительно стабильнее.
В некоторых случаях, если вы не хотите использовать системные команды, можно попробовать «помочь» платформе правильно позиционироваться. Рассмотрим пример кода, который принудительно устанавливает родителя и активизирует объект после переключения режима:
Процедура ВключитьИерархиюБезопасно()
ТекЭлемент = ТекущийЭлемент();
РодительЭлемента = ТекЭлемент.Родитель;
// Выключаем обновление формы на время манипуляций
Форма.Обновить(0);
ИерархическийСписок(1, 1);
// Принудительно задаем контекст родителя
ИспользоватьРодителя(РодительЭлемента);
АктивизироватьОбъект(ТекЭлемент);
Форма.Обновить(1);
КонецПроцедуры
Однако отметим, что данный метод помогает не всегда. Если дерево «сломалось» на уровне системного кэша, установка родителя может не вернуть пропавшие группы.
При использовании внешних компонент в 1С 7.7 важно правильно настроить среду окружения. Разберем несколько полезных настроек, которые повышают стабильность работы интерфейса:
TurboBL. Он оптимизирует выполнение кода встроенного языка, что косвенно снижает вероятность конфликтов при отрисовке.
// Пример настройки в Global.ert
Настройки = СоздатьОбъект("УправлениеНастройками");
Настройки.Включить("Оптимизация");
Настройки.Включить("TurboBL");
Мы выяснили, что баг метода ИерархическийСписок() в 1С 7.7 вызван особенностями виртуального списка и его чувствительностью к выполнению кода в момент перерисовки. Для решения проблемы рекомендуем:
32866 через объект Окна) как самое надежное и простое в реализации.Эти методы позволят вам избежать «пропадания» данных и сделают интерфейс вашего приложения на базе 1С 7.7 более профессиональным и стабильным.