Почему пропадает фокус с табличного документа после вызова сервера и что такое «ОсновнойЭлементФормы» в 1С?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При разработке и кастомизации управляемых форм в платформе «1С:Предприятие 8» программисты нередко сталкиваются с неочевидным поведением интерфейса. Одной из таких загадочных проблем является внезапная потеря фокуса ввода на табличном документе или таблице формы сразу после возврата с серверного вызова. Особенно странно это выглядит, когда у пользователей с полными правами всё работает корректно, а у рядовых сотрудников с ограниченными правами навигация с клавиатуры по ячейкам таблицы ломается, и фокус смещается на некий недокументированный объект ОсновнойЭлементФормы.

В этой статье мы подробно разберем природу этого явления, выясним, откуда берется скрытый системный элемент формы, почему на него перескакивает фокус при установке режима «Только просмотр» и как элегантно обойти это ограничение платформы, сохранив удобство работы для пользователей.

Что представляет собой «ОсновнойЭлементФормы»?

Если вы попробуете найти упоминание объекта ОсновнойЭлементФормы в официальной документации или в синтакс-помощнике, ваши поиски не увенчаются успехом. Данный элемент является скрытым системным типом платформы, предназначенным для внутреннего управления структурой управляемой формы.

Проанализируем его ключевые особенности:

  1. Физический тип объекта: Если в процессе отладки перехватить состояние формы и проверить тип текущего элемента через конструкцию ТипЗнч(ЭтаФорма.ТекущийЭлемент), платформа вернет тип «Макет формы».
  2. Отсутствие стандартных свойств: У этого объекта нет привычных для обычных элементов интерфейса свойств, таких как Имя, Заголовок, Доступность или коллекция Элементы. Из-за этого любой код, который пытается динамически анализировать текущий элемент (например, конструкции вида ЭтаФорма.ТекущийЭлемент.Имя), при попадании фокуса на этот системный объект немедленно завершится аварийно с ошибкой «Поле объекта не обнаружено».
  3. Причина появления на форме: В управляемом приложении свойство формы ТекущийЭлемент физически не может принимать значение Неопределено, если форма открыта. Платформа всегда должна держать фокус на каком-то объекте. Если на управляемой форме нет ни одного интерактивного элемента, доступного для фокусировки (например, создана абсолютно пустая форма или все элементы скрыты/заблокированы), платформа автоматически назначает текущим элементом именно этот базовый контейнер — ОсновнойЭлементФормы.

Таким образом, сброс фокуса на ОсновнойЭлементФормы — это защитный механизм платформы, который срабатывает, когда активный элемент внезапно становится недоступным для интерактивного взаимодействия.

Выясним теперь, почему это происходит именно после серверного вызова и только у пользователей без полных прав.

Почему слетает фокус при «ТолькоПросмотр = Истина» после вызова сервера?

Рассмотрим детально цепочку событий, которая приводит к потере фокуса:

  1. Интерактивное действие: Пользователь перемещается по ячейкам табличного документа (ТД). При активизации ячейки срабатывает клиентский обработчик события (например, ПриАктивизацииОбласти или ПриАктивизацииСтроки), который инициирует контекстный вызов сервера для получения детальных данных по текущему объекту.
  2. Разграничение прав доступа: Для пользователей с ограниченными правами в коде обработки или в настройках прав программно устанавливается свойство табличного документа ТолькоПросмотр = Истина. Это логично, так как обычным пользователям запрещено редактировать выведенный отчет или макет, им нужно только просматривать данные.
  3. Возврат с сервера на клиент: После выполнения серверной процедуры управление возвращается на клиентскую сторону. В этот момент платформа «1С:Предприятие» полностью обновляет состояние элементов управляемой формы, перерисовывает интерфейс и выполняет повторную инициализацию фокуса ввода.
  4. Логика анализа доступности: Опрашивая элементы формы, платформа видит, что для табличного документа установлено свойство ТолькоПросмотр = Истина. С точки зрения логики управляемого интерфейса, такой элемент считается неинтерактивным (доступным только для чтения, в котором нельзя изменять данные программно или вручную). Платформа принимает решение, что удерживать фокус клавиатурного ввода на нередактируемом элементе бессмысленно, и пытается перенести его на другое доступное для изменения поле.
  5. Перенос фокуса «в никуда»: Если на форме отсутствуют другие активные поля ввода, поддерживающие редактирование, или они не настроены на получение автоматического фокуса, платформа сбрасывает фокус ввода. И так как свойство ТекущийЭлемент не может остаться пустым, в него записывается системный макет ОсновнойЭлементФормы. Как результат — клавиатурная навигация (стрелки вверх, вниз, влево, вправо) по табличному документу полностью блокируется до тех пор, пока пользователь снова физически не кликнет мышкой по ячейкам таблицы.

При полных правах свойство ТолькоПросмотр у табличного документа чаще всего остается в значении Ложь (либо из-за логики программного кода, либо по умолчанию), поэтому администраторы системы с этой проблемой не сталкиваются.

Разберем практические способы решения этой проблемы.

Способ 1. Использование защиты областей табличного документа

Самый надежный и правильный способ сохранить фокус и навигацию с клавиатуры — отказаться от глобальной установки свойства ТолькоПросмотр = Истина для всего элемента формы. Вместо этого мы можем заблокировать редактирование ячеек на уровне самого табличного документа, оставив сам элемент формы доступным и интерактивным.

Проанализируем программный код, который решает эту задачу:


// Вместо этого кода, который ломает фокус:
// Элементы.ТабличныйДокумент.ТолькоПросмотр = Истина;

// Используем защиту ячеек табличного документа:
ТабличныйДокумент = Элементы.ТабличныйДокумент;
ТабличныйДокумент.Защита = Истина;

// Для предотвращения случайного изменения данных в конкретных областях:
ОбластьМакета = ТабличныйДокумент.Область("R1C1:R100C100");
ОбластьМакета.Защита = Истина;

При таком подходе элемент формы «Табличный документ» остается полноценным участником интерактивного взаимодействия, платформа не считает его «мертвым» при обновлении формы после возврата с сервера, и фокус ввода стабильно удерживается на выделенной ячейке.

Способ 2. Принудительное восстановление фокуса на клиенте

Если по каким-то причинам использование свойства ТолькоПросмотр = Истина для элемента формы является обязательным и вы не можете от него отказаться, мы можем принудительно возвращать фокус на табличный документ сразу после завершения серверного вызова.

Для реализации этого метода рассмотрим следующий пример клиент-серверного взаимодействия:


&НаКлиенте
Процедура ТабличныйДокументПриАктивизацииОбласти(Элемент)
    
    // Выполняем серверный вызов для получения детальной информации
    ПолучитьПодробныеДанныеНаСервере();
    
    // Принудительно возвращаем фокус на элемент формы после обновления состояния
    ЭтаФорма.ТекущийЭлемент = Элементы.ТабличныйДокумент;
    
КонецПроцедуры

&НаСервере
Процедура ПолучитьПодробныеДанныеНаСервере()
    // Здесь выполняется логика запроса данных без полных прав
    // Например, заполнение соседних реквизитов формы данными о текущей ячейке
КонецПроцедуры

Этот способ гарантирует, что даже если платформа попытается сбросить фокус на ОсновнойЭлементФормы, клиентский код мгновенно вернет его обратно на табличный документ, и пользователь сможет продолжить беспрепятственную навигацию с помощью клавиатуры.

Способ 3. Безопасная проверка текущего элемента формы во избежание ошибок

Если в модуле вашей управляемой формы написан код, выполняющий анализ текущего элемента или обход коллекции элементов формы, обязательно добавьте проверку на тип или наличие имени у текущего элемента. Это убережет вашу конфигурацию от неожиданных аварийных завершений работы пользователей при встрече со скрытым системным макетом.

Разберем пример безопасного кода проверки текущего элемента:


&НаКлиенте
Процедура ПроверитьТекущийЭлемент()
    
    АктивныйЭлемент = ЭтаФорма.ТекущийЭлемент;
    
    // Проверяем, существует ли элемент с таким именем в коллекции элементов формы
    Если АктивныйЭлемент <> Неопределено И Элементы.Найти(АктивныйЭлемент.Имя) <> Неопределено Тогда
        // Безопасно работаем со свойствами элемента
        ИмяЭлемента = АктивныйЭлемент.Имя;
        Если ИмяЭлемента = "ТабличныйДокумент" Тогда
            // Выполняем логику для табличного документа
        КонецЕсли;
    Иначе
        // Сработал "ОсновнойЭлементФормы" или фокус сброшен на системный макет
        // Код не упадет с ошибкой "Поле объекта не обнаружено (Имя)"
    КонецЕсли;
    
КонецПроцедуры

Резюме и рекомендации

Подведем итоги нашего исследования проблемы:

Применяя данные подходы на практике, мы обеспечим стабильную работу интерфейса, корректную навигацию с клавиатуры и предотвратим потенциальные ошибки в коде управляемых форм «1С:Предприятия».

← На главную