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