В процессе разработки и поддержки конфигураций 1С на обычных формах (например, в таких популярных решениях, как «Бухгалтерия для Казахстана 2.0», «Комплексная автоматизация 1.1» или «Управление производственным предприятием 1.3») программисты часто сталкиваются с неочевидным поведением интерфейсных элементов. Типичный пример подобной сложности — работа с документом Платежное поручение исходящее.
В зависимости от выбранного вида операции (например, оплата поставщику, перечисление заработной платы, уплата налогов или пенсионных взносов) на форме документа должны отображаться совершенно разные наборы полей и табличных частей. Из-за этого разработчику бывает трудно с ходу обнаружить нужную табличную часть в конфигураторе или настроить программное изменение ее колонок. Рассмотрим подробно, как устроена эта механика и как решить сопутствующие технические проблемы.
Проанализируем архитектуру построения интерфейса в сложных документах на обычных формах. Когда мы открываем форму документа в конфигураторе, перед нами предстает стандартный макет. Однако при переключении видов операций на форме динамически появляются целые таблицы (например, список сотрудников для перечисления зарплаты или пенсионных отчислений), которых визуально на макете формы не видно.
Выясним причину этого поведения. Разработчики типовых конфигураций используют специальный элемент управления — Панель (обычно с именем ПанельОсновная, ПанельПлатежи или аналогичным). Эта панель состоит из множества вкладок (страниц), на каждой из которых размещено свое Табличное поле, связанное с конкретной табличной частью документа (Зарплата, ПенсионныеВзносы, ПеречислениеНалогов и т.д.). В конфигураторе эти страницы наложены друг на друга, и визуально отображается только одна из них (активная по умолчанию).
Чтобы быстро найти нужную табличную часть и начать редактирование ее свойств или обработчиков событий, выполним следующие шаги:
ТабличноеПолеЗарплата или ТабличноеПолеПенсионныеВзносы).После этого мы можем легко зайти в свойства табличного поля, настроить состав колонок, а также перейти к его событиям в модуле формы.
Разберем другую частую проблему, с которой сталкиваются разработчики при работе с динамическими табличными частями. Допустим, нам необходимо при изменении значения в одной колонке строки автоматически рассчитывать или подставлять значение в другую колонку этой же строки.
Посмотрим на типичную ошибку начинающих разработчиков. Попытка написать следующий код в обработчике события не приводит к какому-либо результату (значение в интерфейсе и в базе данных просто не меняется):
ЭлементыФормы.ТабличноеПолеЗарплата.ТекущиеДанные.ИмяКолонки = "123";
Выясним, почему система никак не реагирует на этот код. В платформе 1С табличные части документов имеют строгую типизацию. Если колонка табличной части (например, Сотрудник или ФизЛицо) имеет тип данных, отличный от строки (например, ссылку на справочник СправочникСсылка.ФизическиеЛица), то попытка записать туда строковое значение "123" будет проигнорирована ядром платформы. Типы данных должны строго совпадать.
Для того чтобы успешно изменить значение в текущей строке табличного поля, мы должны предварительно получить объект нужного типа (например, ссылку на элемент справочника) и только после этого присвоить его свойству ТекущиеДанные. Рассмотрим корректный пример реализации:
// Получаем строку, с которой в данный момент работает пользователь
СтрокаТабличнойЧасти = ЭлементыФормы.ТабличноеПолеЗарплата.ТекущиеДанные;
Если СтрокаТабличнойЧасти <> Неопределено Тогда
// Ищем ссылку на нужного сотрудника по коду или иному уникальному идентификатору
СсылкаНаСотрудника = Справочники.СотрудникиОрганизаций.НайтиПоКоду("000000123");
// Проверяем, что элемент успешно найден в базе данных
Если Не СсылкаНаСотрудника.Пустая() Тогда
// Присваиваем ссылочное значение строго соответствующего типа
СтрокаТабличнойЧасти.Сотрудник = СсылкаНаСотрудника;
КонецЕсли;
КонецЕсли;
Этот подход гарантирует, что изменения будут корректно приняты платформой, отобразятся на форме и запишутся в документ при его сохранении.
Для реализации интерактивной логики (когда одно поле заполняется в зависимости от другого прямо во время ввода данных пользователем) важно правильно выбрать событие. Рассмотрим по шагам, как настроить автоматическое заполнение связанных реквизитов.
Наиболее подходящим событием для этого является ПриИзменении конкретного элемента управления (колонки) внутри табличного поля. Настроим обработчик этого события для колонки Сотрудник:
Процедура ТабличноеПолеЗарплатаСотрудникПриИзменении(Элемент)
// Получаем текущие данные редактируемой строки
ТекущаяСтрока = ЭлементыФормы.ТабличноеПолеЗарплата.ТекущиеДанные;
Если ТекущаяСтрока = Неопределено Тогда
Возврат;
КонецЕсли;
// Автоматически подставляем подразделение организации, закрепленное за сотрудником
Если ЗначениеЗаполнено(ТекущаяСтрока.Сотрудник) Тогда
ТекущаяСтрока.ПодразделениеОрганизации = ТекущаяСтрока.Сотрудник.ПодразделениеОрганизации;
Иначе
ТекущаяСтрока.ПодразделениеОрганизации = Справочники.ПодразделенияОрганизаций.ПустаяСсылка();
КонецЕсли;
КонецПроцедуры
Обратите внимание: мы используем свойство ТекущиеДанные, а не ТекущаяСтрока. В обычных формах свойство ТекущаяСтрока табличного поля часто возвращает лишь индекс строки или ссылку на строку, работа с которой может приводить к избыточным обращениям к серверу базы данных. Свойство ТекущиеДанные возвращает непосредственный объект строки табличной части (типа СтрокаТабличнойЧасти), изменения в котором отражаются в памяти мгновенно и без лишних накладных расходов.
Иногда возникают ситуации, когда интерактивное изменение данных через элементы формы блокируется какими-либо внутренними механизмами платформы или другими обработчиками ожидания. В таких случаях мы можем прибегнуть к альтернативному способу — прямому изменению данных в объекте документа с последующим принудительным обновлением отображения на форме.
Рассмотрим, как реализовать этот подход программно:
// Получаем индекс текущей строки, выбранной пользователем на форме
ИндексТекущейСтроки = ЭлементыФормы.ТабличноеПолеЗарплата.ТекущаяСтрока.Индекс();
Если ИндексТекущейСтроки <> Неопределено Тогда
// Обращаемся напрямую к табличной части прикладного объекта "ЭтотОбъект" по полученному индексу
СтрокаОбъекта = ЭтотОбъект.Зарплата[ИндексТекущейСтроки];
// Изменяем реквизиты объекта напрямую в оперативной памяти
СтрокаОбъекта.Сумма = 150000;
// Принудительно обновляем элементы формы, чтобы пользователь увидел изменения
ЭлементыФормы.ТабличноеПолеЗарплата.ОбновитьСтроки();
КонецЕсли;
Этот способ является максимально надежным, так как мы работаем непосредственно с данными бизнес-логики документа (коллекцией ЭтотОбъект.Зарплата), минуя возможные ограничения и особенности визуального слоя обычных форм.
Таким образом, комбинируя правильный поиск элементов управления на скрытых страницах панелей в конфигураторе и строгое соблюдение типов данных при работе с ТекущиеДанные, мы получаем полный контроль над поведением сложных документов в конфигурациях 1С на обычных формах.