Как получить значение из активной строки табличной части и передать его в динамический список в 1С

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

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

На первый взгляд задача кажется простой, однако начинающие разработчики часто сталкиваются с неочевидными ошибками. В этой статье мы подробно проанализируем типичные ошибки контекста выполнения (клиент/сервер), разберем правильный алгоритм реализации через параметры запроса и рассмотрим более гибкий и современный подход — использование отборов динамического списка.

Разбор типичных ошибок и причин их возникновения

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

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

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

Выбор оптимального события: ПриАктивизацииСтроки

Единственным верным событием для отслеживания выбора строки пользователем является событие таблицы ПриАктивизацииСтроки. Оно генерируется платформой всякий раз, когда пользователь перемещает курсор по табличной части, добавляет новую строку или когда строка активизируется системой автоматически (например, при открытии формы).

Важная особенность: Событие ПриАктивизацииСтроки вызывается платформой очень часто. Оно может срабатывать при обновлении формы, изменении состава колонок и интерактивных действиях. Если внутри этого обработчика выполнять безусловные серверные вызовы для обновления динамического списка, это приведет к серьезной потере производительности интерфейса (форма будет «зависать» при перемещении стрелками по таблице). Поэтому мы обязательно должны внедрить проверку на изменение значения реквизита.

Рассмотрим два детальных сценария реализации связки элементов управления.

Способ 1. Использование параметров произвольного запроса (классический метод)

Если в вашем динамическом списке используется произвольный запрос, в тексте которого жестко зашито условие с параметром (например, ГДЕ Инцидент.Услуга = &Риск), то нам необходимо динамически менять значение этого параметра на сервере.

Для реализации этого способа выполним следующие шаги:

Шаг 1. Добавим на форму вспомогательный реквизит (переменную контекста формы) с именем ТекущийАктивныйРиск. Этот реквизит будет хранить последнее переданное в список значение, чтобы избежать дублирующих серверных вызовов.

Шаг 2. Создадим на клиенте обработчик события ПриАктивизацииСтроки для нашей таблицы «Причины»:


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

Шаг 3. Реализуем сопутствующую процедуру на сервере для непосредственной установки параметра запроса динамического списка:


&НаСервере
Процедура УстановитьПараметрСпискаНаСервере(ЗначениеРиска)
	
	// Используем стандартный метод установки параметра
	Список.Параметры.УстановитьЗначениеПараметра("Риск", ЗначениеРиска);
	
КонецПроцедуры

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

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

Опытные разработчики 1С рекомендуют уходить от жестко прописанных параметров в секции ГДЕ запроса динамического списка и использовать стандартный механизм отборов компоновщика настроек. Это дает колоссальные преимущества:

Посмотрим, как реализовать установку отбора. Мы разберем два варианта реализации серверной части: с использованием функций БСП (Библиотеки Стандартных Подсистем) и на чистой платформе.

Клиентский обработчик события ПриАктивизацииСтроки в случае использования отборов будет выглядеть следующим образом:


&НаКлиенте
Процедура ПричиныПриАктивизацииСтроки(Элемент)
	
	ТекущиеДанные = Элемент.ТекущиеДанные;
	
	Если ТекущиеДанные = Неопределено Тогда
		// Передаем Неопределено и выключаем отбор
		УстановитьОтборСпискаНаСервере(Неопределено, Ложь);
	Иначе
		УстановитьОтборСпискаНаСервере(ТекущиеДанные.Риск, Истина);
	КонецЕсли;
	
КонецПроцедуры

Вариант А. Установка отбора с использованием типовых функций БСП

Если ваша конфигурация разработана на основе БСП (что справедливо для большинства современных конфигураций, таких как ERP, КА, УТ, БП, ЗУП), вы можете использовать готовую и оптимизированную функцию общего модуля:


&НаСервере
Процедура УстановитьОтборСпискаНаСервере(ЗначениеРиска, ИспользоватьОтбор)
	
	// Типовой метод БСП сам найдет нужный отбор, добавит его при отсутствии или обновит значение
	ОбщегоНазначенияКлиентСервер.УстановитьЭлементОтбораДинамическогоСписка(
		Список, 
		"Услуга", // Имя поля в динамическом списке, по которому накладывается фильтр
		ЗначениеРиска, 
		ВидСравненияКомпоновкиДанных.Равно, 
		, 
		ИспользоватьОтбор
	);
	
КонецПроцедуры

Вариант Б. Установка отбора средствами чистой платформы (без БСП)

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


&НаСервере
Процедура УстановитьОтборСпискаНаСервере(ЗначениеРиска, ИспользоватьОтбор)
	
	ПолеОтбора = Новый ПолеКомпоновкиДанных("Услуга");
	ЭлементОтбора = Неопределено;
	
	// Обходим существующие отборы, чтобы не плодить дубликаты одного и того же поля
	Для Каждого Элемент Из Список.Отбор.Элементы Цикл
		Если Элемент.ЛевоеЗначение = ПолеОтбора Тогда
			ЭлементОтбора = Элемент;
			Прервать;
		КонецЕсли;
	КонецЦикла;
	
	// Если отбор по этому полю еще не был создан, добавляем его в коллекцию
	Если ЭлементОтбора = Неопределено Тогда
		ЭлементОтбора = Список.Отбор.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
		ЭлементОтбора.ЛевоеЗначение = ПолеОтбора;
		ЭлементОтбора.ВидСравнения = ВидСравненияКомпоновкиДанных.Равно;
	КонецЕсли;
	
	// Устанавливаем актуальные параметры использования и значения
	ЭлементОтбора.Использование = ИспользоватьОтбор;
	ЭлементОтбора.ПравоеЗначение = ЗначениеРиска;
	
КонецПроцедуры

Подведем итоги

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

  1. Никогда не обращаться к интерфейсным свойствам (таким как ТекущиеДанные) на сервере.
  2. Использовать событие ПриАктивизацииСтроки табличной части для оперативного отслеживания действий пользователя на клиенте.
  3. Минимизировать количество серверных вызовов с помощью клиентской проверки на изменение значения (кэширование в реквизит формы) и отдавать предпочтение гибким механизмам программного отбора компоновщика данных вместо жестких параметров в запросах.
← На главную