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