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