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