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