При разработке на платформе 1С:Предприятие 8.3 программисты часто сталкиваются с неприятным визуальным эффектом: после редактирования строки или выполнения расчетов в обработчике ПриИзменении, таблица (динамический список или табличная часть) самопроизвольно прокручивается к самой первой строке. Это сбивает пользователя, особенно если в документе десятки или сотни позиций. В этой статье мы подробно разберем причины такого поведения платформы и изучим несколько способов решения проблемы — от простых настроек свойств до программных манипуляций с идентификаторами строк.
Прежде всего, проанализируем ситуацию. Платформа 1С перерисовывает элементы управления на форме каждый раз, когда меняются их ключевые визуальные свойства или когда происходит рассинхронизация данных между клиентом и сервером. Рассмотрим основные причины сброса фокуса:
Элементы.ИмяТаблицыКолонка.ТекстПодвала, платформа инициирует обновление всей структуры таблицы, что приводит к скроллу в начало.Загрузить() для табличных частей или полное обновление запроса в динамическом списке уничтожает старые идентификаторы строк.&НаСервере) внутри обработчика события, платформа пытается восстановить состояние формы при возврате на клиент. Если данных много или структура изменилась, алгоритм восстановления может сработать некорректно.РеквизитФормыВЗначение и затем ЗначениеВРеквизитФормы полностью пересоздает объектную структуру данных формы.Рассмотрим самый эффективный способ обновления итогов в подвале без перерисовки всей таблицы. Вместо того чтобы программно менять текст, мы воспользуемся механизмом связки данных.
Разберем по шагам, как это реализовать:
ИтогКоличество и типом Число).ИтогКоличество.Посмотрим на пример кода в обработчике:
&НаКлиенте
Процедура ТабличнаяЧастьКоличествоПриИзменении(Элемент)
// Получаем текущую строку для расчетов
ТекСтрока = Элементы.ТабличнаяЧасть.ТекущиеДанные;
Если ТекСтрока <> Неопределено Тогда
// Выполняем расчет прямо на клиенте, чтобы не дергать сервер
ТекСтрока.Сумма = ТекСтрока.Количество * ТекСтрока.Цена;
// Обновляем реквизит, привязанный к подвалу
// Это НЕ вызовет перерисовку всей таблицы
ИтогКоличество = Объект.ТабличнаяЧасть.Итог("Количество");
КонецЕсли;
КонецПроцедуры
Поскольку значение в подвале теперь меняется через привязку к данным, 1С обновляет только конкретную ячейку, сохраняя положение курсора и прокрутку неизменными.
Если специфика вашей задачи требует полной перезагрузки коллекции данных, важно помнить, что в управляемых формах строки идентифицируются не по индексу (0, 1, 2...), а по уникальному Идентификатору. Выясним, как принудительно вернуть фокус на нужную строку.
Проанализируем пример кода, который позволяет «запомнить» строку перед обновлением и «вернуться» на нее после:
&НаКлиенте
Процедура ОбновитьТаблицуИСохранитьПозицию()
// Запоминаем идентификатор текущей строки
ИдентификаторСтроки = Элементы.СписокТоваров.ТекущаяСтрока;
// Выполняем действия, которые могли привести к обновлению (например, вызов сервера)
ОбновитьДанныеНаСервере();
// Пытаемся вернуть фокус на ту же строку
Если ИдентификаторСтроки <> Неопределено Тогда
Элементы.СписокТоваров.ТекущаяСтрока = ИдентификаторСтроки;
КонецЕсли;
КонецПроцедуры
Важный нюанс: Этот способ сработает только в том случае, если идентификаторы строк сохранились (например, при частичном изменении данных). Если вы полностью очистили таблицу и загрузили её заново, идентификаторы изменятся, и вам придется искать строку по ключевым значениям (например, по ссылке на номенклатуру).
Часто проблема возникает из-за избыточного использования контекстных серверных вызовов. Рассмотрим, как минимизировать влияние сервера на интерфейс. Выясним причину: при вызове &НаСервере на сервер передается весь контекст формы (все данные всех реквизитов), а при возврате — вся форма обновляется.
Попробуем использовать внеконтекстные вызовы (&НаСервереБезКонтекста). Это работает значительно быстрее и стабильнее для интерфейса:
&НаКлиенте
Процедура ПриИзмененииДанных(Элемент)
ТекДанные = Элементы.Таблица.ТекущиеДанные;
// Передаем только необходимые параметры, а не всю форму
РезультатРасчета = РассчитатьНаСервереБезКонтекста(ТекДанные.Номенклатура, ТекДанные.Количество);
ТекДанные.Результат = РезультатРасчета;
КонецПроцедуры
&НаСервереБезКонтекста
Функция РассчитатьНаСервереБезКонтекста(Знач Товар, Знач Кол)
// Здесь выполняем только логику, не обращаясь к реквизитам формы напрямую
Возврат ПроцедурыИФункцииПользователя.РассчитатьЦену(Товар, Кол);
КонецФункции
Иногда, несмотря на все настройки, фокус все равно «улетает» из активной колонки. В таких случаях мы можем явно указать системе, какой элемент должен быть активным в данный момент. Проанализируем использование свойства ТекущийЭлемент.
В конце вашего обработчика ПриИзменении добавьте следующую строку:
// Возвращаем фокус на тот же элемент, который инициировал изменение
ЭтаФорма.ТекущийЭлемент = Элемент;
Также полезно знать о методе ОбновитьОтображениеДанных(). Рассмотрим его применение: когда вы изменили данные программно, и они должны отобразиться в связанных элементах (например, в итогах или условном оформлении), этот метод заставляет платформу пересчитать визуальную часть без глубокой перерисовки всей формы.
Чтобы ваша таблица работала стабильно и не раздражала пользователя «прыжками»:
ТекстПодвала напрямую в коде, используйте ПутьКДаннымПодвала.&НаСервереБезКонтекста.ТекущийЭлемент в конце процедуры.Следуя этим правилам, вы обеспечите плавную и комфортную работу пользователя с табличными данными в любом самописном документе или обработке.