При разработке интерфейсов на управляемых формах 1С часто возникает задача оперативного подсчета итогов по выбранным пользователем позициям. Например, в платежном календаре бухгалтеру может потребоваться быстро узнать общую сумму по нескольким выделенным заявкам, чтобы оценить остаток денежных средств. Однако стандартное событие таблицы ПриАктивизацииСтроки имеет свои особенности, которые мешают получить актуальные данные в момент изменения выделения. В этой статье мы подробно разберем, почему возникает эта проблема и как ее элегантно решить несколькими способами.
Рассмотрим стандартную ситуацию: разработчик назначает обработчик события ПриАктивизацииСтроки для таблицы формы. Внутри этого обработчика он обращается к свойству Элементы.ИмяТаблицы.ВыделенныеСтроки. Проблема заключается в том, что в момент возникновения события (особенно при снятии выделения с одной из строк с помощью Ctrl + клик) коллекция выделенных строк еще не успевает обновиться внутри платформы. Программа видит "старый" набор строк, и результат суммирования оказывается неверным — сумма включает ту строку, которую пользователь только что исключил из выбора.
Проанализируем причины такого поведения. Событие ПриАктивизацииСтроки срабатывает в момент начала взаимодействия с элементом. Платформа сначала фиксирует факт изменения фокуса или выделения, инициирует событие, и только после выполнения кода обработчика окончательно перерисовывает интерфейс и обновляет связанные коллекции данных. Чтобы обойти это ограничение, нам нужно "отложить" выполнение расчета до того момента, когда платформа завершит все внутренние операции по обновлению коллекции выделенных строк.
Самым эффективным способом решения этой проблемы является использование метода ПодключитьОбработчикОжидания. Разберем этот механизм по шагам. Мы не будем выполнять расчет сразу в событии активизации строки, а лишь дадим команду системе выполнить его через ничтожно малый промежуток времени.
Сначала настроим основное событие таблицы:
&НаКлиенте
Процедура ЗаявкиКОплатеПриАктивизацииСтроки(Элемент)
// Мы подключаем обработчик на 0.1 секунды.
// Параметр "Истина" означает однократный запуск.
ПодключитьОбработчикОжидания("ВыполнитьРасчетСуммыВыделенныхСтрок", 0.1, Истина);
КонецПроцедуры
Обратите внимание на важный нюанс, упомянутый в обсуждении: интервал времени должен быть числом (например, 0.1), а не строкой. Использование строки в качестве интервала является ошибкой, которая приведет к неработоспособности механизма в некоторых версиях платформы.
Теперь создадим саму процедуру расчета. Здесь мы проанализируем ситуацию и используем более современный цикл Для каждого вместо устаревшего Пока, что сделает код читаемее и надежнее:
&НаКлиенте
Процедура ВыполнитьРасчетСуммыВыделенныхСтрок()
Перем ИтоговаяСумма;
ИтоговаяСумма = 0;
// Перебираем идентификаторы выделенных строк
Для Каждого ИдентификаторСтроки Из Элементы.ЗаявкиКОплате.ВыделенныеСтроки Цикл
// Получаем данные конкретной строки по её идентификатору
СтрокаДанных = Элементы.ЗаявкиКОплате.ДанныеСтроки(ИдентификаторСтроки);
Если СтрокаДанных <> Неопределено Тогда
// Накапливаем сумму по нужному реквизиту
ИтоговаяСумма = ИтоговаяСумма + СтрокаДанных.СуммаДокумента;
КонецЕсли;
КонецЦикла;
// Выводим результат в реквизит формы, связанный с полем на экране
Объект.ИтогПоВыделенным = ИтоговаяСумма;
КонецПроцедуры
Выясним причину использования ДанныеСтроки(). Этот метод позволяет получить доступ к данным строки таблицы формы напрямую. Если ваша таблица связана с динамическим списком, обращение напрямую через точку к объекту (как ВыделенныеСтроки[сч].ОбъектОплаты.СуммаДокумента) может вызвать неявный серверный вызов, что существенно замедлит работу интерфейса при выделении большого количества строк. Метод ДанныеСтроки() работает с данными, которые уже кэшированы в форме на клиенте.
Проанализируем ситуацию с точки зрения удобства пользователя (UX). Выделение строк мышкой с зажатой клавишей Ctrl — процесс довольно хрупкий. Одно неосторожное движение или клик без клавиши Ctrl сбросит все выделение, и пользователю придется начинать сборку суммы заново. Если таблица содержит сотни строк, это может вызвать раздражение.
В качестве альтернативы рассмотрим добавление в таблицу специальной колонки "Выбрать" (тип Булево). Посмотрим на плюсы этого решения:
ПриИзменении флажка в строке.В этом случае нам не потребуется обработчик ожидания, так как данные в строке меняются сразу, и мы можем мгновенно пересчитать итог простым перебором всей таблицы или инкрементальным добавлением/вычитанием суммы из общей переменной.
Не стоит забывать, что в платформу 1С уже встроены мощные механизмы анализа данных, о которых пользователи часто не знают. Рассмотрим два основных способа, не требующих написания кода:
Ctrl + F2). Пользователь может выделить ячейку с суммой и нажать кнопку "M+" на панели инструментов 1С. Число попадет в память калькулятора. Выделяя следующие строки и нажимая "M+", он будет аккумулировать сумму. Нажатие "M-" позволит вычесть ошибочно добавленную строку.Если вы все же решили использовать программный метод суммирования по выделенным строкам, проанализируем вопросы производительности. При выделении очень большого количества строк (например, через Ctrl + A) цикл по коллекции ВыделенныеСтроки может занять заметное время. Чтобы интерфейс "не фризил", рекомендуется:
Количество() перед запуском цикла.ПоказатьОповещениеПользователя для вывода результата, чтобы не загромождать форму лишними полями.Выяснив все технические детали, мы видим, что наиболее сбалансированным решением для динамического расчета является сочетание события ПриАктивизацииСтроки и ПодключитьОбработчикОжидания. Это обеспечивает "бесшовный" опыт для пользователя, когда сумма актуализируется мгновенно и без лишних действий.