При разработке в среде 1С:Предприятие (особенно на платформе с использованием Обычных форм) программисты часто сталкиваются со следующей задачей: нужно считать существующий документ из базы данных, программно внести в него изменения в оперативной памяти (без непосредственной записи в базу данных), а затем открыть его форму пользователю, чтобы он мог продолжить редактирование или самостоятельно нажать кнопку «Записать».
Казалось бы, простая последовательность методов должна работать безотказно. Однако на практике разработчики часто сталкиваются с ситуацией, когда открывается либо абсолютно новая (пустая) форма документа, либо форма существующего документа, но без учета сделанных программных изменений. Выясним причину этой проблемы и разберем по шагам, как правильно реализовать данный механизм.
Рассмотрим типичный код, который часто приводит к ошибке:
ДокументОбъект = Ссылка.ПолучитьОбъект();
ПоменятьРеквизитыДокумента(ДокументОбъект); // Изменяем реквизиты в памяти
ФормаДок = ДокументОбъект.ПолучитьФорму("ФормаДокумента");
ФормаДок.Открыть();
При таком подходе платформа 1С может проигнорировать переданный измененный ДокументОбъект и открыть стандартную форму, где реквизиты будут заполнены старыми данными из базы данных. Происходит это по нескольким причинам:
ПолучитьФорму() вернет ссылку на уже существующее окно. Это окно связано с «предыдущей» версией объекта в памяти, и новые программные изменения в нем не отобразятся.ДокументОбъект и основным реквизитом формы может быть нарушена. Платформа инициализирует форму заново на основании ссылки, считывая старые данные из базы.Давайте проанализируем решения, которые помогут гарантированно открыть форму с вашими изменениями.
Чтобы гарантировать, что форма будет отображать именно тот объект, который мы изменили в памяти, необходимо явно связать его с основным реквизитом формы — ДокументОбъект. Этот реквизит всегда присутствует у форм документов в обычном приложении.
Рассмотрим пример кода:
// 1. Получаем объект из базы данных по ссылке
ДокументОбъект = СсылкаНаДокумент.ПолучитьОбъект();
// 2. Вносим необходимые изменения в реквизиты или табличные части
ДокументОбъект.Комментарий = "Изменено программно перед открытием формы";
ДокументОбъект.СуммаДокумента = 15000;
// 3. Получаем форму (можно указывать конкретное имя формы)
ФормаДок = ДокументОбъект.ПолучитьФорму("ФормаДокумента");
// 4. КРИТИЧЕСКИ ВАЖНЫЙ ШАГ: Явно передаем наш измененный объект в форму
ФормаДок.ДокументОбъект = ДокументОбъект;
// 5. Открываем форму пользователю
ФормаДок.Открыть();
Этот способ работает безотказно, так как мы принудительно перезаписываем контекст формы нашим объектом непосредственно перед выводом окна на экран.
Если в конфигурации для документа задана основная форма, и нам нужно открыть именно её, то можно использовать метод ПолучитьФорму() без передачи параметров. В этом случае платформа автоматически связывает контекст измененного объекта с открываемой формой.
Посмотрим на пример:
ТекДокументОбъект = СсылкаНаДокумент.ПолучитьОбъект();
// Модифицируем объект
ТекДокументОбъект.Ответственный = ПараметрыСеанса.ТекущийПользователь;
// Получаем форму по умолчанию
Форма = ТекДокументОбъект.ПолучитьФорму();
Форма.Открыть();
Важное примечание: данный способ сработает корректно только в том случае, если форма этого документа еще не открыта у пользователя на экране.
Если есть вероятность, что пользователь уже открыл форму данного документа, нам нужно получить новый, уникальный экземпляр формы, чтобы применить к нему наши изменения. Для этого используется третий параметр метода ПолучитьФорму() — ключ уникальности.
Синтаксис метода выглядит так: ПолучитьФорму(<ИмяФормы>, <Владелец>, <КлючУникальности>).
Реализуем это на практике:
ДокументОбъект = СсылкаНаДокумент.ПолучитьОбъект();
// Произвольные изменения объекта
ДокументОбъект.Комментарий = "Принудительное обновление формы";
// Генерируем уникальный ключ (например, новый УникальныйИдентификатор)
КлючУникальности = Новый УникальныйИдентификатор;
// Получаем абсолютно новый экземпляр формы
ФормаДок = ДокументОбъект.ПолучитьФорму("ФормаДокумента", , КлючУникальности);
ФормаДок.ДокументОбъект = ДокументОбъект;
ФормаДок.Открыть();
Разработчикам важно не путать синтаксис работы с формами. В управляемом приложении (УФ) концепция работы с незаписанными объектами кардинально отличается, так как там нет прямой возможности передать ДокументОбъект на сторону клиента.
Если вы по ошибке попытаетесь использовать в Обычных формах синтаксис Управляемых форм, например:
// ОШИБКА для обычного приложения! Такой код не сработает:
ФормаЗаказа = ПолучитьФорму("Документ.Заказ.Форма.ФормаДокумента", Новый Структура("Ключ", Ссылка));
Платформа в обычном режиме воспримет второй параметр (структуру) как Владельца формы, что приведет к ошибке выполнения или некорректному поведению интерфейса.
Для сравнения, в Управляемых формах (УФ) аналогичная задача решается через передачу данных формы на сервер и обратно без записи в БД с использованием специальных процедур:
&НаКлиенте
Процедура ИзменитьИОткрытьНаКлиенте()
// 1. Получаем форму по ссылке
ПараметрыФормы = Новый Структура("Ключ", СсылкаНаДокумент);
ФормаДок = ПолучитьФорму("Документ.Заказ.ФормаОбъекта", ПараметрыФормы);
// 2. Получаем данные формы в переменную
ДанныеФормы = ФормаДок.Объект;
// 3. Модифицируем данные на сервере
МодифицироватьНаСервере(ДанныеФормы);
// 4. Копируем измененные данные обратно в форму
КопироватьДанныеФормы(ДанныеФормы, ФормаДок.Объект);
// 5. Открываем форму
ФормаДок.Открыть();
КонецПроцедуры
&НаСервереБезКонтекста
Процедура МодифицироватьНаСервере(ДанныеФормы)
// Преобразуем данные формы в прикладной объект ДокументОбъект
ДокументОбъект = ДанныеФормыВЗначение(ДанныеФормы, Тип("ДокументОбъект.Заказ"));
// Вносим изменения
ДокументОбъект.Комментарий = "Изменено в УФ без записи!";
// Возвращаем изменения обратно в структуру данных формы
ЗначениеВДанныеФормы(ДокументОбъект, ДанныеФормы);
КонецПроцедуры
Резюмируя, при работе в обычном приложении всегда используйте прямое переопределение свойства Форма.ДокументОбъект = ДокументОбъект. Это гарантирует стабильную работу вашего кода и исключает появление пустых или неактуальных форм на экране пользователя.