Как программно отсортировать элементы в группе управляемой формы 1С?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При динамической генерации командного интерфейса на управляемой форме нередко возникает задача упорядочить созданные кнопки или поля. Например, когда пункты подменю добавляются из разных источников и в финале их требуется выстроить по алфавиту заголовков. Попытка решить эту задачу с помощью вспомогательного списка значений и метода Элементы.Переместить часто приводит к ошибке выполнения: «Несоответствие типов (параметр номер '1')». Разберем по шагам, почему возникает эта ошибка, как работает метод перемещения элементов и как правильно реализовать сортировку.

Анализ ошибки: почему возникает несоответствие типов

Рассмотрим исходную ситуацию. В коде выполняется обход подчиненных элементов группы, они помещаются в СписокЗначений, список сортируется, после чего в цикле вызывается перемещение:


Сортировка = Новый СписокЗначений;
Для Каждого Пункт Из ПунктыМеню Цикл
    Сортировка.Добавить(Пункт.Заголовок, Пункт);
КонецЦикла;
Сортировка.СортироватьПоПредставлению();

ПредыдущийЭлемент_ = Сортировка[0];
Для Инд = 1 По Сортировка.Количество() - 1 Цикл
    Пункт = Сортировка[Инд];
    _форма.Элементы.Переместить(Пункт, _элементГруппа, ПредыдущийЭлемент_); 
    ПредыдущийЭлемент_ = Пункт;
КонецЦикла;

Проанализируем этот фрагмент и выясним причину падения платформы. Здесь допущены сразу две принципиальные ошибки:

  1. Неверный порядок параметров при заполнении списка. Метод СписокЗначений.Добавить имеет сигнатуру: Добавить(<Значение>, <Представление>, ...). Передавая в коде Сортировка.Добавить(Пункт.Заголовок, Пункт), разработчик помещает строковый заголовок в свойство Значение, а сам элемент формы — в Представление.
  2. Передача объекта списка вместо элемента формы. При обращении по индексу Сортировка[Инд] возвращается объект типа ЭлементСпискаЗначений, а не сам элемент интерфейса (КнопкаФормы, ПолеФормы и т.д.). Метод Элементы.Переместить ожидает на вход непосредственно элемент формы. Передача ЭлементСпискаЗначений в первый параметр вызывает закономерное исключение. Чтобы получить целевой объект, необходимо обращаться к свойству .Значение.

Особенности синтаксиса метода Элементы.Переместить

Посмотрим на синтаксис метода коллекции ВсеЭлементыФормы:

Переместить(<Элемент>, <Родитель>, <СледующийЭлемент>)

Обратим внимание на третий параметр. Это следующий элемент, то есть элемент, перед которым будет спозиционирован перемещаемый объект. Если передавать туда предыдущий элемент, итоговый порядок кнопок окажется перевернутым или некорректным.

Однако у метода есть важная особенность: если третий параметр опущен или передан как Неопределено, перемещаемый элемент переносится в самый конец списка подчиненных элементов указанного родителя. Это позволяет значительно упростить весь алгоритм: не требуется отслеживать соседние элементы, достаточно поочередно переместить отсортированные объекты в родительскую группу без указания третьего параметра.

Решение 1: Исправление сортировки через СписокЗначений

Скорректируем процедуру с учетом правильного заполнения свойств списка и упрощенного вызова метода Переместить:


Процедура ОтсортироватьЭлементы(_форма, Знач _элементГруппа) Экспорт
    
    Если ТипЗнч(_элементГруппа) = Тип("Строка") Тогда  
        _элементГруппа = _форма.Элементы.Найти(_элементГруппа); 
        Если _элементГруппа = Неопределено Тогда
            Возврат;
        КонецЕсли;
    КонецЕсли;
    
    Если ТипЗнч(_элементГруппа) <> Тип("ГруппаФормы") Тогда  
        Возврат;
    КонецЕсли;
    
    // Заполняем список: Значение - элемент формы, Представление - заголовок для сортировки
    Сортировка = Новый СписокЗначений;
    Для Каждого Элемент Из _элементГруппа.ПодчиненныеЭлементы Цикл
        Сортировка.Добавить(Элемент, Элемент.Заголовок);
    КонецЦикла;
    
    // Сортируем список по строковому представлению
    Сортировка.СортироватьПоПредставлению();
    
    // Последовательно перемещаем элементы в конец группы
    Для Каждого ЭлементСписка Из Сортировка Цикл
        _форма.Элементы.Переместить(ЭлементСписка.Значение, _элементГруппа);
    КонецЦикла;
        
КонецПроцедуры

В этом варианте каждый элемент из отсортированного списка последовательно переносится в конец группы, благодаря чему они выстраиваются в строго заданном порядке возрастания заголовков.

Решение 2: Сортировка через ТаблицуЗначений

Если код выполняется на сервере (например, в процедуре ПриСозданииНаСервере), более наглядным и надежным вариантом выступает использование временной ТаблицыЗначений. Это исключает путаницу между значением и представлением:


ТаблицаСортировки = Новый ТаблицаЗначений;
ТаблицаСортировки.Колонки.Добавить("Заголовок", Новый ОписаниеТипов("Строка"));
ТаблицаСортировки.Колонки.Добавить("Элемент");

Для Каждого Элемент Из _элементГруппа.ПодчиненныеЭлементы Цикл
    НоваяСтрока = ТаблицаСортировки.Добавить();
    НоваяСтрока.Заголовок = Элемент.Заголовок;
    НоваяСтрока.Элемент   = Элемент;
КонецЦикла;

ТаблицаСортировки.Сортировать("Заголовок Возр");

Для Каждого Стр Из ТаблицаСортировки Цикл
    _форма.Элементы.Переместить(Стр.Элемент, _элементГруппа);
КонецЦикла;

Альтернативный подход: правильное добавление элементов с самого начала

Перемещение элементов постфактум создает дополнительную нагрузку на интерфейсную подсистему формы. Если кнопки создаются динамически в коде из массива, структуры или результата запроса, правильнее изначально отсортировать коллекцию исходных данных перед добавлением элементов на форму:

  1. Сортировка исходных данных: сортируем массив названий команд или таблицу настроек до обращения к коллекции Элементы.
  2. Использование метода Элементы.Добавить: добавляем элементы поочередно. Каждый новый элемент естественным образом встает в конец группы, сохраняя порядок отсортированного источника.
  3. Использование метода Элементы.Вставить: если кнопку необходимо внедрить среди уже существующих элементов формы, используем метод Вставить(<Имя>, <ТипЭлемента>, <Родитель>, <СледующийЭлемент>), сразу указывая элемент, перед которым она должна отображаться. Это полностью снимает необходимость вызывать метод Переместить.
← На главную