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