Как из формы обработки открыть форму документа и установить текущую строку в табличной части

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

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

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

Почему не работают стандартные "наивные" попытки?

Начинающие разработчики часто сталкиваются с ошибками при попытке реализовать этот функционал. Давайте разберем типичные ошибки, которые были упомянуты на форуме:

  1. Использование устаревшего метода ПолучитьФорму на уровне ссылки. В управляемом приложении вызов Ссылка.ПолучитьФорму() является некорректным и часто приводит к ошибкам выполнения. Для работы с управляемыми формами следует использовать глобальный метод ОткрытьФорму или ПолучитьФорму глобального контекста.
  2. Попытка позиционирования до открытия формы. Если попытаться установить свойство ТекущаяСтрока до того, как форма фактически создана и инициализирована на клиенте, это действие не возымеет никакого эффекта. Позиционирование должно происходить строго после или в момент инициализации визуальной части формы.
  3. Смешение контекстов (Сервер и Клиент). Свойство элемента формы ТекущаяСтрока доступно только на клиенте. Однако поиск строки по ключевым полям программисты часто пытаются перенести на сервер, что приводит к избыточным вызовам сервера (серверным round-trip) и замедлению работы интерфейса.

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

Способ 1. Прямое позиционирование на клиенте (Оптимальный быстрый вариант)

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

Ключевой нюанс, который важно понимать: на клиенте табличная часть документа представлена типом ДанныеФормыКоллекция, а не привычной серверной ТабличнаяЧасть. Это означает, что метод НайтиСтроки доступен нам прямо на клиенте без какого-либо обращения к серверу. Нам не нужно делать контекстные или внеконтекстные вызовы сервера, чтобы найти внутренний идентификатор строки.

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


&НаКлиенте
Процедура ОткрытьДокументИПозиционировать(Команда)

    // Шаг 1. Готовим параметры для открытия формы существующего документа
    ПараметрыФормы = Новый Структура;
    ПараметрыФормы.Вставить("Ключ", Объект.ДокументСсылка); // Ссылка на наш документ

    // Шаг 2. Открываем форму документа и получаем ее объект
    ФормаДокумента = ОткрытьФорму(
        "Документ.ПоступлениеТоваровУслуг.Форма.ФормаДокумента", 
        ПараметрыФормы, 
        ЭтаФорма
    );

    // Шаг 3. Ищем нужную строку в коллекции ДанныеФормыКоллекция на клиенте
    ПараметрыОтбора = Новый Структура;
    ПараметрыОтбора.Вставить("Номенклатура", Объект.ЦелеваяНоменклатура);
    
    НайденныеСтроки = ФормаДокумента.Объект.Товары.НайтиСтроки(ПараметрыОтбора);

    // Шаг 4. Если строка найдена, получаем ее уникальный идентификатор и активизируем
    Если НайденныеСтроки.Количество() > 0 Тогда
        // Свойству ТекущаяСтрока таблицы формы нужно присваивать именно числовой Идентификатор строки,
        // который мы получаем методом ПолучитьИдентификатор()
        ИдентификаторСтроки = НайденныеСтроки[0].ПолучитьИдентификатор();
        ФормаДокумента.Элементы.Товары.ТекущаяСтрока = ИдентификаторСтроки;
    КонецЕсли;

КонецПроцедуры

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

Способ 2. Архитектурно правильный подход через параметры формы (Слабая связь)

Чтобы избежать жесткой зависимости между обработкой и структурой формы документа, мы можем применить паттерн слабой связи. Вместо того чтобы управлять элементами чужой формы "снаружи", мы передадим целевые параметры поиска "внутрь" формы при ее открытии, а логику позиционирования полностью инкапсулируем в самой форме документа (или реализуем через расширение конфигурации, если мы работаем с типовой системой, например, ЗУП 3.1 или ERP).

Разберем по шагам, как это выглядит в коде.

Шаг 1. Вызов из формы обработки (отправитель):


&НаКлиенте
Процедура ОткрытьДокументСПараметрами(Команда)

    ПараметрыФормы = Новый Структура;
    ПараметрыФормы.Вставить("Ключ", Объект.ДокументСсылка);
    
    // Передаем параметр, по которому форма документа сама поймет, куда ей нужно встать
    ПараметрыФормы.Вставить("ПараметрПозиционированияСотрудник", Объект.ЦелевойСотрудник);

    ОткрытьФорму(
        "Документ.ИзменениеШтатногоРасписания.Форма.ФормаДокумента", 
        ПараметрыФормы, 
        ЭтаФорма
    );

КонецПроцедуры

Шаг 2. Обработка параметров в форме документа (получатель):

В модуле формы документа (в обработчике события ПриОткрытии на клиенте) мы считываем переданные параметры и позиционируем курсор:


&НаКлиенте
Процедура ПриОткрытии(Отказ)
    
    // Проверяем, был ли передан специальный параметр для позиционирования
    Если Параметры.Свойство("ПараметрПозиционированияСотрудник") Тогда
        
        ПараметрыПоиска = Новый Структура("Сотрудник", Параметры.ПараметрПозиционированияСотрудник);
        НайденныеСтроки = Объект.Позиции.НайтиСтроки(ПараметрыПоиска);
        
        Если НайденныеСтроки.Количество() > 0 Тогда
            Элементы.Позиции.ТекущаяСтрока = НайденныеСтроки[0].ПолучитьИдентификатор();
        КонецЕсли;
        
    КонецЕсли;
    
КонецПроцедуры

Преимущества такого подхода очевидны: форма обработки ничего не знает о внутренней структуре элементов формы документа. Она лишь декларирует свое намерение: "Я хочу открыть документ и сфокусироваться на сотруднике Х". А форма документа сама решает, в какой табличной части находится этот сотрудник и как именно выполнить фокусировку.

Способ 3. Прямое позиционирование по известному индексу

Иногда возникают ситуации, когда нам заранее известен физический индекс строки в табличной части (например, мы точно знаем, что нам нужна третья строка по порядку). В таком случае использовать тяжелый метод НайтиСтроки() нет необходимости. Мы можем напрямую обратиться к коллекции по индексу.

Посмотрим на пример реализации такого позиционирования:


&НаКлиенте
Процедура ПозиционироватьПоИндексу(ИндексСтроки)

    ПараметрыФормы = Новый Структура("Ключ", Объект.ДокументСсылка);
    ФормаДокумента = ОткрытьФорму("Документ.ПоступлениеТоваровУслуг.Форма.ФормаДокумента", ПараметрыФормы);

    КоллекцияСтрок = ФормаДокумента.Объект.Товары;

    // Проверяем, что индекс не выходит за границы коллекции табличной части
    Если ИндексСтроки >= 0 И ИндексСтроки < КоллекцияСтрок.Количество() Тогда
        
        // Получаем объект строки данных по индексу
        СтрокаДанных = КоллекцияСтрок[ИндексСтроки];
        
        // Устанавливаем текущую строку через идентификатор
        ФормаДокумента.Элементы.Товары.ТекущаяСтрока = СтрокаДанных.ПолучитьИдентификатор();
        
    КонецЕсли;

КонецПроцедуры

Этот способ работает мгновенно, поскольку не требует перебора коллекции и выделения памяти под структуры поиска.

Важные детали юзабилити: Визуальный фокус и неактивные вкладки

Бывает так, что разработчик написал корректный код позиционирования, свойство ТекущаяСтрока заполнилось правильным идентификатором, но пользователь при открытии формы все равно не видит выделенную строку. Это происходит по двум причинам:

  1. Таблица находится на неактивной в данный момент вкладке (например, на странице "Дополнительно", а активна вкладка "Основное").
  2. Фокус ввода находится на другом элементе формы (например, в поле ввода номера или даты документа), из-за чего выделение строки в табличной части визуально отображается блеклым цветом и не бросается в глаза.

Для того чтобы гарантировать стопроцентную видимость строки пользователю, мы должны программно активизировать нужную страницу панели и передать фокус непосредственно самой табличной части. Рассмотрим, как усовершенствовать наш код:


&НаКлиенте
Процедура ОткрытьИАктивизироватьВизуально()

    ПараметрыФормы = Новый Структура("Ключ", Объект.ДокументСсылка);
    ФормаДокумента = ОткрытьФорму("Документ.ПоступлениеТоваровУслуг.Форма.ФормаДокумента", ПараметрыФормы);

    НайденныеСтроки = ФормаДокумента.Объект.Товары.НайтиСтроки(Новый Структура("Номенклатура", Объект.ЦелеваяНоменклатура));

    Если НайденныеСтроки.Количество() > 0 Тогда
        
        // 1. Устанавливаем текущую строку таблицы
        ИдентификаторСтроки = НайденныеСтроки[0].ПолучитьИдентификатор();
        ФормаДокумента.Элементы.Товары.ТекущаяСтрока = ИдентификаторСтроки;
        
        // 2. Активизируем вкладку, на которой физически расположена табличная часть "Товары"
        // (актуально, если на форме используется многостраничная группа элементов)
        ФормаДокумента.Элементы.ГруппаПанелиФормы.ТекущаяСтраница = ФормаДокумента.Элементы.СтраницаТовары;
        
        // 3. Передаем фокус ввода на саму таблицу формы
        ФормаДокумента.ТекущийЭлемент = ФормаДокумента.Элементы.Товары;
        
    КонецЕсли;

КонецПроцедуры

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

Подводя итог, отметим: для простых разовых доработок и внешних отчетов вполне подходит прямое управление свойствами открытой формы на клиенте через метод ПолучитьИдентификатор(). Однако для крупных и масштабируемых систем (таких как ЗУП 3.1, ERP или УТ) лучшим решением всегда будет передача целевых параметров и обработка логики позиционирования внутри самой открываемой формы.

← На главную