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