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