В процессе разработки в среде «1С:Предприятие 8.3» программисты часто сталкиваются с запросами пользователей, которые хотят повысить скорость и удобство своей работы. Типичный пример такого запроса — возможность быстро просматривать содержимое документа (его реквизиты, состав табличной части, контрагента, сумму) прямо в форме списка, не открывая сам документ в отдельном окне. Это экономит время и избавляет от необходимости совершать лишние клики.
Первое побуждение начинающего разработчика — открыть форму документа программно в событии ПриАктивизацииСтроки динамического списка. Однако попытка сделать это «в лоб» (тем более с использованием модальных окон) приводит к критическим ошибкам проектирования интерфейса, зависаниям программы и недовольству пользователей. В этой статье мы подробно разберем, почему стандартный подход с открытием формы не работает, и рассмотрим несколько профессиональных и элегантных способов реализации панели предпросмотра (превью) в управляемом интерфейсе 1С.
Давайте проанализируем, к каким последствиям приводит вызов открытия формы (особенно модальной) непосредственно внутри обработчика ПриАктивизацииСтроки:
ПриАктивизацииСтроки крайне опасно выполнять контекстные серверные вызовы. Если серверный вызов неявно спровоцирует обновление или перерисовку динамического списка, платформа повторно инициирует событие активизации строки. Это приведет к бесконечной рекурсии и аварийному завершению работы программы по превышению стека вызовов.Рассмотрим, какими правильными альтернативными способами мы можем решить задачу предпросмотра.
Если пользователю достаточно видеть простые реквизиты шапки документа (например, комментарий, ответственного, статус или адрес доставки), которые уже выбраны в динамическом списке, мы можем обойтись без написания кода.
Разберем этот процесс по шагам в конфигураторе:
Список, найдем ветку ТекущиеДанные и перетащим нужные реквизиты в созданную группу.Платформа автоматически настроит путь к данным для этих элементов интерфейса. Он будет выглядеть так: Элементы.Список.ТекущиеДанные.ИмяРеквизита. При перемещении курсора по списку платформа сама, без единой строчки кода, будет обновлять значения в этих полях, отображая информацию для текущей строки.
Важное ограничение: этот метод идеально подходит для простых полей, но он абсолютно неприменим, если вам нужно вывести табличную часть документа (например, список товаров). Табличные части не выбираются динамическим списком по умолчанию, и связать их напрямую через ТекущиеДанные невозможно.
Для вывода более сложных данных (включая табличные части) нам потребуется написать код. Чтобы избежать зависания интерфейса при быстром скроллинге, мы применим важнейший паттерн разработки — асинхронный вызов через обработчик ожидания (Debounce). Суть метода заключается в том, что мы запрашиваем данные с сервера не мгновенно при переходе на строку, а только тогда, когда пользователь остановил курсор на строке на короткое время (например, на 0.2 секунды).
Выполним пошаговую реализацию этого механизма:
Шаг 1. Подготовка интерфейса формы списка.
Добавим на форму списка новую таблицу формы. Назовем её ПревьюТовары. В качестве источника данных для этой таблицы создадим реквизит формы с типом ТаблицаЗначений (назовем его ТоварыПревью) и добавим в него необходимые колонки (например, Номенклатура, Количество, Цена, Сумма).
Шаг 2. Написание кода в модуле формы.
В модуле формы списка определим переменную для хранения текущей выбранной ссылки и опишем обработчики событий:
&НаКлиенте
Перем ТекущаяСсылкаДляПревью;
&НаКлиенте
Процедура СписокПриАктивизацииСтроки(Элемент)
// Каждый раз при смене строки сбрасываем старый обработчик ожидания
ОтключитьОбработчикОжидания("ПодключитьПревьюПослеПаузы");
ТекущиеДанные = Элементы.Список.ТекущиеДанные;
Если ТекущиеДанные = Неопределено Тогда
ТоварыПревью.Очистить();
Возврат;
КонецЕсли;
// Запоминаем ссылку, которую нужно обработать
ТекущаяСсылкаДляПревью = ТекущиеДанные.Ссылка;
// Подключаем однократный обработчик ожидания с паузой в 0.2 секунды
ПодключитьОбработчикОжидания("ПодключитьПревьюПослеПаузы", 0.2, Истина);
КонецПроцедуры
&НаКлиенте
Процедура ПодключитьПревьюПослеПаузы()
// Проверяем, что ссылка не пустая и действительно изменилась
Если ЗначениеЗаполнено(ТекущаяСсылкаДляПревью) Тогда
ПолучитьДанныеДокументаНаСервере(ТекущаяСсылкаДляПревью);
КонецЕсли;
КонецПроцедуры
Шаг 3. Запрос данных на сервере без контекста.
Для обеспечения максимальной скорости работы мы будем использовать неконтекстный серверный вызов &НаСервереБезКонтекста. Это позволит передавать между клиентом и сервером только необходимый минимум данных, минуя передачу всего контекста формы списка.
&НаСервереБезКонтекста
Функция ПолучитьТабличнуюЧастьДокумента(Знач СсылкаНаДокумент)
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ПоступлениеПродукцииТовары.Номенклатура КАК Номенклатура,
| ПоступлениеПродукцииТовары.Количество КАК Количество,
| ПоступлениеПродукцииТовары.Цена КАК Цена,
| ПоступлениеПродукцииТовары.Сумма КАК Сумма
|ИЗ
| Документ.ПоступлениеПродукции.Товары КАК ПоступлениеПродукцииТовары
|ГДЕ
| ПоступлениеПродукцииТовары.Ссылка = &СсылкаНаДокумент";
Запрос.УстановитьПараметр("СсылкаНаДокумент", СсылкаНаДокумент);
Возврат Запрос.Выполнить().Выгрузить();
КонецФункции
&НаСервере
Процедура ПолучитьДанныеДокументаНаСервере(Знач СсылкаНаДокумент)
// Получаем таблицу товаров быстрым запросом на сервере
ТаблицаРезультат = ПолучитьТабличнуюЧастьДокумента(СсылкаНаДокумент);
// Загружаем полученные данные в реквизит формы списка
ТоварыПревью.Загрузить(ТаблицаРезультат);
КонецПроцедуры
Благодаря использованию обработчика ожидания и неконтекстного запроса, интерфейс формы списка остается отзывчивым, плавным и не зависает даже при интенсивной прокрутке списка пользователем.
В современных конфигурациях 1С (таких как «1С:Документооборот 3.0» или ERP) разработчики все чаще уходят от стандартного набора полей ввода к более современному отображению данных. Использование элемента Поле HTML-документа позволяет сформировать красивую, компактную и информативную карточку предпросмотра.
Давайте рассмотрим, как реализовать этот подход:
АдресHTMLПремью с типом Строка.АдресHTMLПремью.Посмотрим на пример реализации формирования HTML-строки:
&НаСервереБезКонтекста
Функция СформироватьHTMLПредпросмотра(Знач СсылкаНаДокумент)
// Выберем данные документа быстрым запросом
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Док.Номер КАК Номер,
| Док.Дата КАК Дата,
| Док.Контрагент.Наименование КАК Контрагент,
| Док.СуммаДокумента КАК Сумма,
| Док.Комментарий КАК Комментарий
|ИЗ
| Документ.ПоступлениеПродукции КАК Док
|ГДЕ
| Док.Ссылка = &Ссылка";
Запрос.УстановитьПараметр("Ссылка", СсылкаНаДокумент);
Выборка = Запрос.Выполнить().Выбрать();
Если Не Выборка.Следующий() Тогда
Возврат "<html><body>Документ не найден</body></html>";
КонецЕсли;
// Формируем красивый HTML-шаблон со стилями
HTMLТекст = "<html><head><style>
|body { font-family: Arial, sans-serif; margin: 10px; background-color: #f9f9f9; color: #333; }
|.card { border: 1px solid #ccc; border-radius: 5px; padding: 15px; background-color: #fff; box-shadow: 0 2px 4px rgba(0,0,0,0.1); }
|.title { font-size: 16px; font-weight: bold; color: #1c53a2; margin-bottom: 10px; }
|.row { margin-bottom: 5px; }
|.label { font-weight: bold; color: #666; }
|</style></head><body>";
HTMLТекст = HTMLТекст + "<div class='card'>";
HTMLТекст = HTMLТекст + "<div class='title'>Документ № " + Выборка.Номер + " от " + Формат(Выборка.Дата, "ДФ=dd.MM.yyyy") + "</div>";
HTMLТекст = HTMLТекст + "<div class='row'><span class='label'>Контрагент:</span> " + Выборка.Контрагент + "</div>";
HTMLТекст = HTMLТекст + "<div class='row'><span class='label'>Сумма:</span> " + Формат(Выборка.Сумма, "ЧДЦ=2; ЧГ=3") + " руб.</div>";
Если ЗначениеЗаполнено(Выборка.Комментарий) Тогда
HTMLТекст = HTMLТекст + "<div class='row'><span class='label'>Комментарий:</span> <i>" + Выборка.Комментарий + "</i></div>";
КонецЕсли;
HTMLТекст = HTMLТекст + "</div></body></html>";
Возврат HTMLТекст;
КонецФункции
&НаСервере
Процедура ОбновитьHTMLПанель(Знач СсылкаНаДокумент)
АдресHTMLПремью = СформироватьHTMLПредпросмотра(СсылкаНаДокумент);
КонецПроцедуры
Такой интерфейс выглядит крайне профессионально, легко адаптируется под любые требования заказчика к дизайну и позволяет компактно выводить ключевую информацию на экраны с любым разрешением.
Если бизнес-логика задачи все-таки требует открыть полноценную форму документа при определенном действии пользователя (например, по двойному клику или нажатию специальной кнопки «Быстрый просмотр»), необходимо соблюдать стандарты разработки фирмы «1С». Помните, что использование классических модальных окон в современных конфигурациях запрещено!
Чтобы открыть форму документа в режиме блокировки только формы списка (без полной блокировки всей системы и без использования модальности), следует применять свойство РежимОткрытияОкнаФормы.БлокироватьОкноВладельца.
Рассмотрим пример правильного вызова:
&НаКлиенте
Процедура СписокВыбор(Элемент, ВыбраннаяСтрока, Поле, СтандартнаяОбработка)
// Отменяем стандартное открытие формы в полноэкранном режиме
СтандартнаяОбработка = Ложь;
ПараметрыФормы = Новый Структура;
ПараметрыФормы.Вставить("Ключ", ВыбраннаяСтрока);
// Открываем форму с блокировкой только родительского окна списка
ОткрытьФорму("Документ.ПоступлениеПродукции.ФормаОбъекта",
ПараметрыФормы,
ЭтаФорма,
Истина, // Уникальность
,
,
,
РежимОткрытияОкнаФормы.БлокироватьОкноВладельца);
КонецПроцедуры
При таком подходе форма документа откроется поверх формы списка в виде отдельной всплывающей панели. Пользователь сможет просмотреть и отредактировать все необходимые данные, а после закрытия формы списка управление беспрепятственно вернется к исходному окну.
Мы проанализировали несколько подходов к проектированию интерфейса формы списка и реализации предпросмотра данных. Давайте обобщим полученные знания:
ПриАктивизацииСтроки.ТекущиеДанные.Применение этих простых правил позволит вам создавать быстрые, отзывчивые и интуитивно понятные интерфейсы, которые по достоинству оценят пользователи ваших конфигураций.