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