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