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