Как открыть обычную форму незаписанного измененного документа в 1С?

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

При разработке в среде 1С:Предприятие (особенно на платформе с использованием Обычных форм) программисты часто сталкиваются со следующей задачей: нужно считать существующий документ из базы данных, программно внести в него изменения в оперативной памяти (без непосредственной записи в базу данных), а затем открыть его форму пользователю, чтобы он мог продолжить редактирование или самостоятельно нажать кнопку «Записать».

Казалось бы, простая последовательность методов должна работать безотказно. Однако на практике разработчики часто сталкиваются с ситуацией, когда открывается либо абсолютно новая (пустая) форма документа, либо форма существующего документа, но без учета сделанных программных изменений. Выясним причину этой проблемы и разберем по шагам, как правильно реализовать данный механизм.

В чем заключается основная проблема?

Рассмотрим типичный код, который часто приводит к ошибке:


ДокументОбъект = Ссылка.ПолучитьОбъект();
ПоменятьРеквизитыДокумента(ДокументОбъект); // Изменяем реквизиты в памяти
ФормаДок = ДокументОбъект.ПолучитьФорму("ФормаДокумента");
ФормаДок.Открыть();

При таком подходе платформа 1С может проигнорировать переданный измененный ДокументОбъект и открыть стандартную форму, где реквизиты будут заполнены старыми данными из базы данных. Происходит это по нескольким причинам:

  1. Форма уже открыта на экране. Если у пользователя уже открыта форма этого документа, метод ПолучитьФорму() вернет ссылку на уже существующее окно. Это окно связано с «предыдущей» версией объекта в памяти, и новые программные изменения в нем не отобразятся.
  2. Потеря связи с контекстом. При получении неосновной формы или при указании конкретного имени формы связь между переменной ДокументОбъект и основным реквизитом формы может быть нарушена. Платформа инициализирует форму заново на основании ссылки, считывая старые данные из базы.
  3. Путаница между технологиями ОФ и УФ. Попытки использовать методы управляемого приложения (например, передачу структуры параметров с ключом «Ключ») в обычном приложении приводят к непредсказуемому поведению системы.

Давайте проанализируем решения, которые помогут гарантированно открыть форму с вашими изменениями.

Решение 1. Явная привязка объекта к форме (наиболее надежный способ)

Чтобы гарантировать, что форма будет отображать именно тот объект, который мы изменили в памяти, необходимо явно связать его с основным реквизитом формы — ДокументОбъект. Этот реквизит всегда присутствует у форм документов в обычном приложении.

Рассмотрим пример кода:


// 1. Получаем объект из базы данных по ссылке
ДокументОбъект = СсылкаНаДокумент.ПолучитьОбъект();

// 2. Вносим необходимые изменения в реквизиты или табличные части
ДокументОбъект.Комментарий = "Изменено программно перед открытием формы";
ДокументОбъект.СуммаДокумента = 15000;

// 3. Получаем форму (можно указывать конкретное имя формы)
ФормаДок = ДокументОбъект.ПолучитьФорму("ФормаДокумента");

// 4. КРИТИЧЕСКИ ВАЖНЫЙ ШАГ: Явно передаем наш измененный объект в форму
ФормаДок.ДокументОбъект = ДокументОбъект;

// 5. Открываем форму пользователю
ФормаДок.Открыть();

Этот способ работает безотказно, так как мы принудительно перезаписываем контекст формы нашим объектом непосредственно перед выводом окна на экран.

Решение 2. Использование формы по умолчанию

Если в конфигурации для документа задана основная форма, и нам нужно открыть именно её, то можно использовать метод ПолучитьФорму() без передачи параметров. В этом случае платформа автоматически связывает контекст измененного объекта с открываемой формой.

Посмотрим на пример:


ТекДокументОбъект = СсылкаНаДокумент.ПолучитьОбъект();

// Модифицируем объект
ТекДокументОбъект.Ответственный = ПараметрыСеанса.ТекущийПользователь;

// Получаем форму по умолчанию
Форма = ТекДокументОбъект.ПолучитьФорму();
Форма.Открыть();

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

Что делать, если форма уже открыта? (Использование уникальности)

Если есть вероятность, что пользователь уже открыл форму данного документа, нам нужно получить новый, уникальный экземпляр формы, чтобы применить к нему наши изменения. Для этого используется третий параметр метода ПолучитьФорму() — ключ уникальности.

Синтаксис метода выглядит так: ПолучитьФорму(<ИмяФормы>, <Владелец>, <КлючУникальности>).

Реализуем это на практике:


ДокументОбъект = СсылкаНаДокумент.ПолучитьОбъект();
// Произвольные изменения объекта
ДокументОбъект.Комментарий = "Принудительное обновление формы";

// Генерируем уникальный ключ (например, новый УникальныйИдентификатор)
КлючУникальности = Новый УникальныйИдентификатор;

// Получаем абсолютно новый экземпляр формы
ФормаДок = ДокументОбъект.ПолучитьФорму("ФормаДокумента", , КлючУникальности);
ФормаДок.ДокументОбъект = ДокументОбъект;
ФормаДок.Открыть();

Различие Обычных (ОФ) и Управляемых форм (УФ)

Разработчикам важно не путать синтаксис работы с формами. В управляемом приложении (УФ) концепция работы с незаписанными объектами кардинально отличается, так как там нет прямой возможности передать ДокументОбъект на сторону клиента.

Если вы по ошибке попытаетесь использовать в Обычных формах синтаксис Управляемых форм, например:


// ОШИБКА для обычного приложения! Такой код не сработает:
ФормаЗаказа = ПолучитьФорму("Документ.Заказ.Форма.ФормаДокумента", Новый Структура("Ключ", Ссылка));

Платформа в обычном режиме воспримет второй параметр (структуру) как Владельца формы, что приведет к ошибке выполнения или некорректному поведению интерфейса.

Для сравнения, в Управляемых формах (УФ) аналогичная задача решается через передачу данных формы на сервер и обратно без записи в БД с использованием специальных процедур:


&НаКлиенте
Процедура ИзменитьИОткрытьНаКлиенте()
    // 1. Получаем форму по ссылке
    ПараметрыФормы = Новый Структура("Ключ", СсылкаНаДокумент);
    ФормаДок = ПолучитьФорму("Документ.Заказ.ФормаОбъекта", ПараметрыФормы);
    
    // 2. Получаем данные формы в переменную
    ДанныеФормы = ФормаДок.Объект;
    
    // 3. Модифицируем данные на сервере
    МодифицироватьНаСервере(ДанныеФормы);
    
    // 4. Копируем измененные данные обратно в форму
    КопироватьДанныеФормы(ДанныеФормы, ФормаДок.Объект);
    
    // 5. Открываем форму
    ФормаДок.Открыть();
КонецПроцедуры

&НаСервереБезКонтекста
Процедура МодифицироватьНаСервере(ДанныеФормы)
    // Преобразуем данные формы в прикладной объект ДокументОбъект
    ДокументОбъект = ДанныеФормыВЗначение(ДанныеФормы, Тип("ДокументОбъект.Заказ"));
    
    // Вносим изменения
    ДокументОбъект.Комментарий = "Изменено в УФ без записи!";
    
    // Возвращаем изменения обратно в структуру данных формы
    ЗначениеВДанныеФормы(ДокументОбъект, ДанныеФормы);
КонецПроцедуры

Резюмируя, при работе в обычном приложении всегда используйте прямое переопределение свойства Форма.ДокументОбъект = ДокументОбъект. Это гарантирует стабильную работу вашего кода и исключает появление пустых или неактуальных форм на экране пользователя.

← На главную