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