Как передать единицы измерения из табличной части справочника Номенклатура в форму документа в 1С 8.3 на обычных формах?

Программист 1С v8.3 (Обычные формы)
← На главную

При работе с конфигурациями 1С:Предприятие 8.3, особенно на обычных формах, часто возникает задача передачи данных из одного объекта в другой. В нашем случае, мы рассмотрим ситуацию, когда необходимо перенести информацию о единицах измерения, хранящихся в табличной части элемента справочника Номенклатура, в табличную часть документа, чтобы пользователь мог выбрать нужную единицу из списка, относящегося именно к выбранной номенклатуре. Это типичный сценарий, требующий внимательного подхода, поскольку стандартные механизмы могут быть не всегда очевидны или достаточны.

Первоначальная идея часто связана с использованием Связей Параметров Выбора. Однако, как мы выясним, этот механизм имеет свои ограничения и не всегда подходит для динамического формирования списков на основе сложных структур данных, таких как табличные части других объектов. Мы покажем, как решить эту задачу более гибким и мощным способом – через программное формирование списка выбора.

Почему Связи Параметров Выбора могут не подойти для нашей задачи?

Прежде всего, давайте разберемся, почему попытка использования Связей Параметров Выбора (СПВ) в данном контексте оказалась неэффективной. Автор темы справедливо отметил, что его текущая связь Отбор.ЕдиницаИзмерения(Элементы.Операции.Текущие данные.Номенклатура) не работает. И здесь кроется ключевое понимание:

  1. Назначение Связей Параметров Выбора: Связи Параметров Выбора предназначены для установки декларативного отбора на список выбора справочника или перечисления. Они позволяют ограничить предлагаемые пользователю элементы на основе значений других реквизитов формы. Например, если у нас есть поле "Контрагент", а затем поле "Договор", то мы можем настроить СПВ для поля "Договор", чтобы оно показывало только договоры выбранного контрагента (Отбор.Владелец = Контрагент). Это работает отлично, если "Договор" – это ссылка на справочник "Договоры", у которого есть реквизит "Владелец", ссылающийся на "Контрагента".
  2. Ограничения для табличных частей: Наша задача сложнее. Единицы измерения не просто являются ссылкой на справочник "КлассификаторЕдиницИзмерения". Они хранятся в табличной части "Реквизиты" справочника "Номенклатура". Это означает, что для каждой конкретной номенклатуры может быть свой набор единиц измерения, которые не являются универсальным списком, а формируются динамически. Механизм СПВ не умеет "заглядывать" внутрь табличной части другого объекта и извлекать оттуда список значений для динамического формирования отбора. Он работает с реквизитами самого объекта, а не с его вложенными табличными частями.
  3. Необходимость формирования уникального списка: Мы хотим, чтобы для каждой выбранной номенклатуры в документе пользователь видел только те единицы измерения, которые привязаны к этой конкретной номенклатуре через ее табличную часть. Это не просто отбор из общего списка единиц, а формирование уникального списка на лету.

Таким образом, для решения нашей задачи нам потребуется более гибкий подход, который предоставит полный контроль над формированием списка выбора. И такой подход существует.

Эффективное решение: Программное формирование списка выбора через событие "НачалоВыбораИзСписка"

В 1С 8.3 на обычных формах одним из наиболее мощных и гибких инструментов для динамического формирования списка выбора является обработка события НачалоВыбораИзСписка для поля ввода. Этот метод позволяет нам полностью перехватить стандартный механизм выбора и программно определить, какие элементы будут предложены пользователю. Рассмотрим это решение по шагам.

Шаг 1: Подготовка элемента формы в документе

Прежде чем писать код, убедимся, что поле ввода для ЕдиницыИзмерения в табличной части вашего документа настроено правильно:

  1. Перейдите в форму элемента документа, в котором вы хотите производить выбор единиц измерения.
  2. Найдите элемент управления, привязанный к реквизиту ЕдиницаИзмерения в табличной части документа.
  3. В свойствах этого элемента управления установите флаг КнопкаСпискаВыбора. Это обеспечит появление кнопки, которая вызывает наш динамический список.
  4. Снимите флаг КнопкаВыбора. Если этот флаг будет установлен, то стандартный механизм выбора из справочника будет работать параллельно с нашим программным, что может привести к нежелательному поведению. Мы хотим полностью контролировать процесс выбора.
  5. Создайте обработчик события НачалоВыбораИзСписка для этого элемента формы. Это делается двойным кликом по полю события в палитре свойств элемента.

Шаг 2: Доступ к данным текущей строки документа и выбранной номенклатуры

Внутри обработчика события НачалоВыбораИзСписка нам нужно сначала получить доступ к текущей строке табличной части документа, где происходит выбор, а затем получить ссылку на выбранную в этой строке номенклатуру.

Мы будем работать в модуле формы документа. Для доступа к элементам формы в обычных формах часто используется коллекция ЭлементыФормы. Если код находится в модуле формы, для большей ясности и корректности можно использовать префикс ЭтаФорма..


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

Важно: Обратите внимание на использование ЭтаФорма.ЭлементыФормы. В обычных формах это наиболее надежный способ обращения к элементам управления формы из ее модуля.

Шаг 3: Доступ к табличной части номенклатуры и извлечение единиц измерения

Как мы выяснили из обсуждения, в справочнике Номенклатура единицы измерения хранятся в табличной части с именем Реквизиты, а сам реквизит называется ЕдиницаИзмерения. Теперь, когда у нас есть объект НоменклатураОбъект, мы можем получить доступ к этой табличной части и перебрать ее, чтобы собрать все необходимые единицы измерения.

Продолжаем наш код:


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

Шаг 4: Анализ и улучшение кода

Давайте подробнее разберем каждый аспект предложенного кода и рассмотрим возможные улучшения и нюансы:

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

Альтернативные сценарии и дальнейшие соображения

Предложенное решение является наиболее прямым и эффективным для описанной ситуации. Однако, стоит рассмотреть несколько дополнительных моментов, которые могут возникнуть в более сложных сценариях:

  1. Единицы измерения в регистре сведений: В некоторых типовых конфигурациях 1С (например, Управление Торговлей, ERP), единицы измерения для номенклатуры могут храниться не в табличной части самого справочника, а в отдельном регистре сведений (например, "ЕдиницыИзмеренияНоменклатуры"). В таком случае, для получения списка единиц потребуется выполнить запрос к этому регистру с отбором по текущей номенклатуре. Это потребует использования объектов Запрос и выполнения запроса на сервере, если данные не кешированы.
  2. Производительность: Если табличная часть Реквизиты у номенклатуры очень большая (сотни или тысячи строк), то каждый вызов ПолучитьОбъект() и перебор табличной части может влиять на производительность. Однако, для большинства реальных сценариев, количество единиц измерения для одной номенклатуры обычно не превышает десятков, что делает данный подход вполне приемлемым.
  3. Кэширование данных: Если одна и та же номенклатура выбирается многократно, можно рассмотреть механизмы кэширования списка единиц измерения, чтобы избежать повторного чтения объекта номенклатуры из базы данных. Однако, это усложнит код и обычно не требуется для простых случаев.
  4. Улучшение пользовательского интерфейса: Если список единиц измерения для номенклатуры все равно получается большим, можно добавить функционал поиска или фильтрации непосредственно в выпадающий список. Это, однако, потребует более сложной реализации и, возможно, использования динамического списка или пользовательского элемента управления.

Заключение

Мы с вами подробно рассмотрели, как эффективно передать единицы измерения из табличной части справочника Номенклатура в форму документа в 1С 8.3, работая с обычными формами. Мы выяснили, что Связи Параметров Выбора не всегда подходят для динамического формирования списков из сложных структур данных, и вместо этого использовали программное формирование списка выбора через событие НачалоВыбораИзСписка.

Этот метод дает нам полный контроль над тем, что будет показано пользователю, позволяя динамически собирать данные из табличных частей связанных объектов. Помните о важных нюансах, таких как отключение стандартной обработки выбора, правильный доступ к элементам формы через ЭтаФорма.ЭлементыФормы и обязательное получение объекта по ссылке с помощью ПолучитьОбъект() для доступа к его табличным частям. Применяя эти знания, вы сможете решать аналогичные задачи передачи данных между объектами в 1С 8.3 с высокой гибкостью и эффективностью.

← На главную