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