Как исправить ошибку "Несоответствие типов" при использовании КопироватьДанныеФормы() в 1С?

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

Часто при разработке на платформе 1С возникает задача передать данные из одной формы в другую. Например, пользователь нажимает кнопку "Заполнить" в документе, открывается вспомогательная форма, в ней производятся расчеты или выбор данных, и результат нужно вернуть в исходный документ. Один из методов, который приходит на ум — КопироватьДанныеФормы(), но его неправильное использование приводит к ошибке "Ошибка Несоответствие типов (параметр номер '1')". Давайте вместе разберемся, почему она возникает и как правильно организовать обмен данными между формами.

Анализируем причину ошибки

Проанализируем ситуацию. У нас есть основная форма документа и вспомогательная, которая открывается для заполнения. Мы хотим скопировать данные из вспомогательной формы в основную. Ошибка говорит нам, что в первый параметр функции КопироватьДанныеФормы(<Источник>, <Приемник>) мы передали значение не того типа, который она ожидает.

Обратимся к синтаксис-помощнику. Метод КопироватьДанныеФормы() предназначен для копирования именно данных формы, а не всей формы целиком. Это означает, что в качестве источника он ожидает переменную одного из следующих типов:

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

Практический совет: если вы столкнулись с подобной ошибкой, первым делом поставьте точку останова перед строкой с вызовом проблемной функции и проверьте в отладчике тип переменной, которую вы передаете в качестве первого параметра. Это самый быстрый способ подтвердить причину проблемы.

Правильные способы передачи данных между формами

Прямой доступ к данным одной открытой формы из другой — не самая лучшая практика. Это создает сильную зависимость между формами и усложняет код. Платформа 1С предлагает стандартные и надежные механизмы для решения этой задачи. Рассмотрим два основных.

Способ 1: Модальное открытие формы и возврат значения

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

Разберем по шагам:

  1. В основной форме документа мы вызываем открытие вспомогательной формы с помощью метода ОткрытьФормуМодально(). Выполнение кода в этом месте остановится и будет ждать, пока открытая форма не закроется.
  2. Во вспомогательной форме пользователь выполняет необходимые действия. Перед закрытием мы формируем результат (например, в виде структуры) и передаем его в метод Закрыть().
  3. После закрытия вспомогательной формы, выполнение кода в основной форме продолжается. Результат, который мы передали в метод Закрыть(), становится возвращаемым значением функции ОткрытьФормуМодально().
  4. Мы проверяем полученный результат и используем его для заполнения реквизитов нашей основной формы.

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

Код в основной форме документа (например, по кнопке "Заполнить"):


&НаКлиенте
Процедура Заполнить(Команда)
    // Открываем форму модально и ждем результат
    РезультатЗаполнения = ОткрытьФормуМодально("Обработка.МояОбработкаЗаполнения.Форма.Форма");
    
    // Проверяем, что форма вернула непустой результат
    Если РезультатЗаполнения <> Неопределено Тогда
        // Здесь мы обрабатываем полученные данные.
        // Например, копируем значения в реквизиты объекта.
        Объект.Контрагент = РезультатЗаполнения.Контрагент;
        Объект.СуммаДокумента = РезультатЗаполнения.Сумма;
        // и так далее...
    КонецЕсли;
КонецПроцедуры

Код во вспомогательной форме (например, по кнопке "Передать данные"):


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

Этот способ надежен и прост, но его недостаток в блокировке интерфейса, что может быть неудобно, особенно в веб-клиенте.

Способ 2: Немодальный вызов с использованием механизма оповещений

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

Разберем по шагам:

  1. В основной форме мы создаем ОписаниеОповещения. Это специальный объект, который "помнит", какую процедуру нужно вызвать, когда произойдет событие.
  2. Мы открываем вспомогательную форму методом ОткрытьФорму(), передавая в него созданное описание оповещения. Выполнение кода не останавливается.
  3. Во вспомогательной форме, когда данные готовы, мы вызываем метод Оповестить(). В этот метод мы передаем имя события (любая строка) и сами данные.
  4. Платформа автоматически находит форму, которая ждет оповещения, и вызывает в ней процедуру-обработчик, имя которой мы указали в ОписаниеОповещения. Данные, переданные в Оповестить(), приходят в эту процедуру в качестве параметра.

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

Код в основной форме документа:


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

// Экспортная процедура, которая будет вызвана автоматически после оповещения
&НаКлиенте
Процедура ПослеЗаполнения(Результат, ДополнительныеПараметры) Экспорт
    // Проверяем, что к нам пришли данные (может прийти Неопределено, если форму просто закрыли)
    Если Результат <> Неопределено Тогда
        // Обрабатываем результат точно так же, как и в модальном варианте
        Объект.Контрагент = Результат.Контрагент;
        Объект.СуммаДокумента = Результат.Сумма;
    КонецЕсли;
КонецПроцедуры

Код во вспомогательной форме:


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

Этот метод является предпочтительным для разработки в современных конфигурациях.

Когда же использовать КопироватьДанныеФормы()?

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

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

Пример использования:


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

&НаКлиенте
Процедура Пересчитать()
    // Получаем с сервера обновленные данные
    ОбновленныеДанныеОбъекта = ПересчитатьДанныеНаСервере();
    
    // А вот здесь КопироватьДанныеФормы() на своем месте!
    // Мы копируем данные из структуры (ОбновленныеДанныеОбъекта)
    // в данные основного реквизита формы (Объект).
    КопироватьДанныеФормы(ОбновленныеДанныеОбъекта, Объект);
КонецПроцедуры

Таким образом, запомним простое правило: для передачи данных между формами используем модальные вызовы или механизм оповещений. Для обновления данных внутри формы (например, после серверного вызова) — КопироватьДанныеФормы() является отличным инструментом.

← На главную