При разработке и доработке конфигураций на платформе 1С:Предприятие 7.7 мы часто сталкиваемся со специфическими особенностями поведения интерфейса. Одной из таких классических проблем является программная активация нужной строки в табличной части документа. Ситуация усложняется, если данные подгружаются динамически в фоновом режиме (например, с использованием механизма ОбработкаОжидания).
Разберем типичный сценарий: в открытую форму документа с табличной частью из сторонней программы периодически загружаются новые строки. В коде вызывается стандартный метод АктивизироватьСтроку(), и в отладчике мы даже видим, что переход происходит. Однако в момент окончательного обновления формы и перерисовки интерфейса ядро 1С 7.7 принудительно сбрасывает визуальный фокус и возвращает курсор на первую строку.
Часто программисты пытаются обойти это через "псевдо-закрытие" формы в процедуре ПриЗакрытии(). Но этот костыль имеет критический недостаток — платформа видит флаг модифицированности и выдает пользователю системный вопрос: "Сохранить документ? Да, нет, отмена". Если записывать документ принудительно для сброса флага, это может нарушить логику работы пользователя.
Рассмотрим более элегантные и надежные способы решения этой задачи, которые позволят сохранить фокус на нужной строке без лишних вопросов от системы.
Проанализируем самый изящный способ, не требующий внешних компонент. Идея заключается в том, чтобы временно заблокировать перерисовку интерфейса документа вызовом модального окна.
Сделаем это по шагам:
АктиваторСтроки.
// Передаем контекст текущего документа в обработку
ОткрытьФормуМодально("Обработка.АктиваторСтроки", Контекст);
АктиваторСтроки. В предопределенной процедуре ПриОткрытии() пропишем следующий код:
Процедура ПриОткрытии()
// Активизируем строку через переданный контекст документа
// (предполагается, что нужный номер строки мы вычислили заранее или передали)
Форма.Параметр.АктивизироватьСтроку(НужныйНомерСтроки);
// Мгновенно отменяем открытие формы обработки
СтатусВозврата(0);
Возврат;
КонецПроцедуры
Как это работает: При вызове модального окна движок 1С приостанавливает стандартный цикл обновления родительской формы (документа). В этот момент мы даем команду на активацию строки, после чего модальное окно тут же прерывает собственное открытие командой СтатусВозврата(0). В результате 1С не успевает запустить процедуру сброса курсора на первую строку, и фокус остается ровно там, где мы указали. И самое главное — никаких вопросов о сохранении документа не появляется.
Поскольку принудительный сброс фокуса происходит именно в момент завершения процедуры загрузки новых строк, стандартный вызов АктивизироватьСтроку() внутри этой же процедуры бесполезен.
Посмотрим на решение с использованием цепочки таймеров:
ОбработкаОжидания регулярно опрашивает стороннюю программу и загружает новые данные в табличную часть.
// Конец процедуры загрузки данных
ОбработкаОжидания("УстановкаФокуса", 1);
УстановкаФокуса(), которая выполнит действие уже после того, как форма обновилась:
Процедура УстановкаФокуса()
// Отключаем таймер, передав пустую строку
ОбработкаОжидания("", 0);
// Теперь безопасно активизируем строку
АктивизироватьСтроку(НужныйНомерСтроки);
КонецПроцедуры
Этот метод гарантирует, что команда активации сработает в уже перерисованном интерфейсе.
Если программные методы 1С подводят, мы можем воздействовать на форму на уровне операционной системы Windows. Суть метода — программно "нажать" клавишу стрелки "Вниз" нужное количество раз.
Разберем пример реализации через системный COM-объект:
// Вычисляем, сколько раз нужно нажать "Вниз"
Смещение = НужныйНомерСтроки - 1; // Так как мы находимся на первой строке
Если Смещение > 0 Тогда
WshShell = СоздатьОбъект("WScript.Shell");
Для Индекс = 1 По Смещение Цикл
WshShell.SendKeys("{DOWN}");
КонецЦикла;
КонецЕсли;
Осторожно: Данный метод работает безотказно и не затрагивает флаг модифицированности, однако у него есть недостаток. Если в момент эмуляции пользователь переключится на другое окно (например, откроет браузер), нажатия клавиш {DOWN} уйдут в это стороннее активное окно.
Чтобы избежать проблемы с перехватом фокуса другими приложениями из предыдущего способа, рассмотрим использование популярной внешней компоненты FormEx.
Сама компонента не имеет отдельного магического метода для жесткой активации строки, игнорирующего платформу, но у нее есть отличный объект Сервис с методом ЭмулироватьКлавиатуру().
Сервис = СоздатьОбъект("Сервис");
// Эмуляция нажатия стрелки вниз
// В отличие от WScript.Shell, FormEx посылает команды напрямую в окно 1С
Сервис.ЭмулироватьКлавиатуру(40); // 40 - код клавиши VK_DOWN
Эмуляция через FormEx отрабатывает строго в контексте приложения 1С. Даже если окно программы свернуто или перекрыто другими окнами, сдвиг курсора произойдет корректно именно в нашей табличной части.
Мы проанализировали четыре рабочих способа обойти системное ограничение платформы 1С 7.7 при работе с текущей строкой. Если в конфигурации не используются внешние компоненты, наиболее надежным и "чистым" с точки зрения архитектуры является Способ 1 (с модальным открытием фиктивной обработки) или Способ 2 (отложенный вызов). Они гарантированно избавят ваших пользователей от раздражающих окон с предложением сохранить документ после каждого фонового обновления данных.