Как реализовать выбор и динамическое изменение типа значения для колонки таблицы значений в 1С

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

В процессе разработки интерфейсов в среде «1С:Предприятие» часто возникает задача предоставить пользователю максимальную гибкость при работе с табличными данными. Типичный пример — необходимость динамически изменять тип данных программно созданной колонки таблицы значений. Однако разработчики сразу сталкиваются с двумя серьезными платформенными ограничениями:

  1. Невозможно напрямую изменить свойство ТипЗначения у уже существующей колонки таблицы значений.
  2. В платформе отсутствует штатное событие «При нажатии на заголовок колонки» для табличных частей и таблиц формы.

В этой статье мы подробно разберем, как обойти эти ограничения, рассмотрим проверенные практические методы реализации данной задачи как для обычных, так и для управляемых форм, а также приведем готовые примеры кода.

Решение проблемы №1: Динамическое изменение типа данных существующей колонки

Если мы попытаемся программно перезаписать свойство ТипЗначения у колонки таблицы значений напрямую, платформа вызовет ошибку выполнения. Чтобы обойти это системное ограничение, нам необходимо применить обходной алгоритм пересоздания колонки.

Разберем классический алгоритм для объекта ТаблицаЗначений в коде:

  1. Создаем новую временную колонку во временной или текущей таблице значений с нужным (новым) типом данных.
  2. Перебираем все строки таблицы и копируем данные из старой колонки во временную, выполняя приведение типов (например, используя метод ПривестиЗначение() для описания типов).
  3. Удаляем исходную колонку с устаревшим типом данных.
  4. Создаем новую колонку с исходным именем и новым типом данных.
  5. Переносим данные из временной колонки назад в только что созданную и удаляем временную колонку.

Особенности работы на управляемых формах (начиная с версии 8.2)

Если таблица значений выведена на управляемую форму и связана с реквизитом формы, простых манипуляций с объектом ТаблицаЗначений будет недостаточно. Связь между элементами формы и реквизитами жестко контролируется платформой. Для изменения типа колонки на управляемой форме нам потребуется использовать серверный метод ИзменитьРеквизиты().

Рассмотрим пример процедуры, выполняющей эту операцию на сервере:


&НаСервере
Процедура ИзменитьТипКолонкиТаблицыФормы(ИмяКолонки, НовыйТипДанных)

    // Определяем пути к реквизитам
    ИмяТаблицыСвязи = "ДеревоДанных"; // Имя вашей таблицы-реквизита на форме
    ПолныйПутьКРеквизиту = ИмяТаблицыСвязи + "." + ИмяКолонки;

    // 1. Подготавливаем массивы для удаления и добавления реквизитов формы
    МассивУдаляемыхРеквизитов = Новый Массив;
    МассивУдаляемыхРеквизитов.Добавить(ПолныйПутьКРеквизиту);

    МассивДобавляемыхРеквизитов = Новый Массив;
    НовыйРеквизит = Новый РеквизитФормы(ИмяКолонки, НовыйТипДанных, ИмяТаблицыСвязи, "Заголовок колонки");
    МассивДобавляемыхРеквизитов.Добавить(НовыйРеквизит);

    // 2. Вызываем транзакционное изменение реквизитов формы
    ИзменитьРеквизиты(МассивДобавляемыхРеквизитов, МассивУдаляемыхРеквизитов);

    // 3. Пересоздаем связанный элемент интерфейса (поле ввода в таблице)
    ИмяЭлементаКолонки = ИмяТаблицыСвязи + ИмяКолонки;
    ЭлементКолонки = Элементы.Найти(ИмяЭлементаКолонки);
    Если ЭлементКолонки <> Неопределено Тогда
        Элементы.Удалить(ЭлементКолонки);
    КонецЕсли;

    НовыйЭлемент = Элементы.Добавить(ИмяЭлементаКолонки, Тип("ПолеФормы"), Элементы[ИмяТаблицыСвязи]);
    НовыйЭлемент.Вид = ВидПоляФормы.ПолеВвода;
    НовыйЭлемент.ПутьКДанным = ПолныйПутьКРеквизиту;

КонецПроцедуры

Решение проблемы №2: Обход отсутствия события «При нажатии на заголовок»

Поскольку перехватить стандартный клик по шапке таблицы штатными средствами невозможно, мы можем применить несколько альтернативных UX/UI решений, которые будут интуитивно понятны пользователю.

Вариант А: Использование контекстного меню (Правый клик мыши)

Это один из самых чистых способов с точки зрения интерфейса. Пользователь кликает правой кнопкой мыши по любой ячейке нужной колонки и выбирает пункт «Изменить тип колонки».

Разберем по шагам, как это реализовать:

  1. В свойствах таблицы формы находим раздел «Контекстное меню» и добавляем туда новую кнопку действия (команду).
  2. В обработчике команды определяем, какая колонка сейчас активна, используя свойство ТекущийЭлемент.
  3. Выводим пользователю список доступных типов и вызываем процедуру пересоздания реквизита.

Посмотрим на пример клиентского кода:


&НаКлиенте
Процедура КомандаИзменитьТипКолонки(Команда)

    ТекущийЭлементТаблицы = Элементы.ДеревоДанных.ТекущийЭлемент;
    Если ТекущийЭлементТаблицы = Неопределено Тогда
        Возврат;
    КонецЕсли;

    // Получаем имя колонки из имени элемента формы
    ИмяКолонки = СтрЗаменить(ТекущийЭлементТаблицы.Имя, "ДеревоДанных", "");
    
    // Формируем список доступных типов для выбора
    СписокВыбораТипов = Новый СписокЗначений;
    СписокВыбораТипов.Добавить(Новый ОписаниеТипов("Строка"), "Текст (Строка)");
    СписокВыбораТипов.Добавить(Новый ОписаниеТипов("Число"), "Числовое значение");
    СписокВыбораТипов.Добавить(Новый ОписаниеТипов("Дата"), "Дата");
    
    // Показываем меню выбора пользователю
    ОписаниеОповещения = Новый ОписаниеОповещения("ПослеВыбораТипаКолонки", ЭтотОбъект, ИмяКолонки);
    ПоказатьВыборИзСписка(ОписаниеОповещения, СписокВыбораТипов, ТекущийЭлементТаблицы);

КонецПроцедуры

&НаКлиенте
Процедура ПослеВыбораТипаКолонки(ВыбранныйЭлемент, ДополнительныеПараметры) Экспорт

    Если ВыбранныйЭлемент = Неопределено Тогда
        Возврат;
    КонецЕсли;

    ИмяКолонки = ДополнительныеПараметры;
    НовыйТипДанных = ВыбранныйЭлемент.Значение;

    // Вызываем серверный метод пересоздания реквизита
    ИзменитьТипКолонкиТаблицыФормы(ИмяКолонки, НовыйТипДанных);

КонецПроцедуры

Вариант Б: Имитация шапки таблицы («Фейковая шапка»)

Если проект требует, чтобы действие происходило именно при нажатии сверху над колонками, мы можем полностью скрыть стандартную шапку таблицы (установив свойство таблицы формы ОтображатьВШапке = Ложь). Вместо нее непосредственно над таблицей мы размещаем горизонтальную группу элементов, в которую программно или визуально добавляем обычные кнопки. Каждая кнопка визуально имитирует заголовок колонки. При нажатии на кнопку-заголовок срабатывает стандартное событие ПриНажатии, где мы открываем диалог выбора типа.

Вариант В: Специальная строка настройки параметров

Мы можем зафиксировать самую первую строку в таблице значений и сделать ее служебной. Например, записать туда текст «[Нажмите для выбора типа колонки]». В обработчиках событий таблицы ПриНачалеРедактирования или Выбор мы анализируем, является ли текущая строка первой. Если да — мы прерываем стандартный ввод данных и открываем диалог изменения типа текущей колонки.

Альтернативный подход: Использование составных типов данных

Чтобы избежать ресурсоемких операций удаления и повторного добавления реквизитов формы на сервере (что может замедлять работу интерфейса при больших объемах данных), мы можем спроектировать архитектуру иначе.

При программном создании колонок мы сразу присваиваем им составной тип данных, содержащий все возможные типы из нашего ограниченного списка. Для того чтобы избавить пользователя от необходимости каждый раз видеть стандартную кнопку выбора типа «Т» при активации ячейки, мы будем динамически управлять доступным типом ввода "на лету" через событие таблицы ПриНачалеРедактирования.

Рассмотрим, как это реализовать:


&НаКлиенте
Процедура ДеревоДанныхПриНачалеРедактирования(Элемент, НоваяСтрока, Копирование)

    ТекущиеДанные = Элементы.ДеревоДанных.ТекущиеДанные;
    Если ТекущиеДанные = Неопределено Тогда
        Возврат;
    КонецЕсли;

    ТекущаяКолонка = Элементы.ДеревоДанных.ТекущийЭлемент;
    ИмяКолонки = ТекущаяКолонка.Имя;

    // Допустим, тип для этой колонки уже был сохранен нами ранее в настройках
    // Ограничиваем доступный для ввода тип конкретной ячейки динамически
    Если ИмяКолонки = "ДеревоДанныхКолонка1" Тогда
        
        // Ограничиваем только типом "Число"
        МассивТипов = Новый Массив;
        МассивТипов.Добавить(Тип("Число"));
        ОграниченныйОписаниеТипов = Новый ОписаниеТипов(МассивТипов);
        
        // Устанавливаем свойства элемента формы текущей колонки
        ТекущаяКолонка.ОграничениеТипа = ОграниченныйОписаниеТипов;
        ТекущаяКолонка.ВыбиратьТип = Ложь; // Отключает кнопку выбора типа "Т"
        
    КонецЕсли;

КонецПроцедуры

Этот подход со временем зарекомендовал себя как наиболее производительный для динамических таблиц на управляемых формах 1С, поскольку он полностью исключает серверные вызовы метода ИзменитьРеквизиты() при изменении типов пользователем.

← На главную