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

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

При работе с управляемыми формами 1С программисты часто сталкиваются с задачей: нужно вызвать вспомогательное окно для ввода данных (например, многострочного текста или сложного расчета) и поместить результат в ячейку таблицы. Однако стандартный подход через прямое присвоение значения реквизиту ТекущиеДанные.ИмяПоля = Значение имеет существенный недостаток. Как только мы выполняем эту строку кода, данные в источнике (таблице значений или табличной части) меняются окончательно. Если после этого пользователь нажмет клавишу Esc или решит отменить редактирование строки, старое значение уже не восстановится.

В этой статье мы подробно разберем, как реализовать ввод данных так, чтобы значение попадало сначала в «поле ввода» (интерфейсный буфер), а не в сам реквизит, сохраняя тем самым механизм транзакционности редактирования строки. Мы рассмотрим несколько эффективных способов решения этой задачи.

Почему прямое присвоение в ТекущиеДанные не работает для отмены

Разберем ситуацию подробнее. В управляемом приложении 1С существует разделение между данными (объектом на сервере или реквизитом формы) и их отображением в элементах формы. Когда пользователь вводит данные руками прямо в ячейку, платформа удерживает эти изменения в специальном состоянии «редактирования». Пока строка не покинута или не нажата кнопка Enter, изменения считаются предварительными. Нажатие Esc просто очищает этот буфер и возвращает отображение старых данных.

Когда же мы пишем в коде ТекущиеДанные.ТекстКомментария = "Новый текст", мы обращаемся напрямую к структуре ДанныеФормыКоллекция. Это действие эквивалентно завершению ввода: платформа считает, что данные изменены программно, и фиксирует их. В этот момент «состояние редактирования» для конкретного поля считается завершенным, и откат к предыдущему значению становится невозможным без специальных ухищрений.

Способ 1. Использование стандартного механизма выбора

Самый «правильный» с точки зрения архитектуры 1С способ — это имитация стандартного выбора значения. Если мы инициируем процесс через событие НачалоВыбора и правильно указываем владельца, платформа сама позаботится о том, чтобы значение попало в поле ввода «интерактивно».

Проанализируем алгоритм реализации этого метода:

  1. В свойствах элемента управления (поля ввода в колонке таблицы) установите флаг КнопкаВыбора в значение Да.
  2. Создайте обработчик события НачалоВыбора для этого поля.
  3. Внутри обработчика вызовите свою форму или диалог, указав в качестве владельца сам элемент формы (поле ввода).

Рассмотрим пример кода для этого метода:


&НаКлиенте
Процедура СписокТоваровКомментарийНачалоВыбора(Элемент, ДанныеВыбора, СтандартнаяОбработка)
    
    СтандартнаяОбработка = Ложь; // Отключаем стандартный выбор справочника
    
    // Параметры для открытия формы редактирования текста
    ПараметрыФормы = Новый Структура;
    ПараметрыФормы.Вставить("Значение", Элементы.СписокТоваров.ТекущиеДанные.Комментарий);
    
    // Важно: Вторым параметром передаем 'Элемент' — это и есть наше поле ввода
    // Платформа запомнит его как владельца выбора
    ОписаниеОповещения = Новый ОписаниеОповещения("ПослеРедактированияТекста", ЭтотОбъект);
    ПоказатьВводСтроки(ОписаниеОповещения, Элементы.СписокТоваров.ТекущиеДанные.Комментарий, "Введите комментарий");
    
КонецПроцедуры

&НаКлиенте
Процедура ПослеРедактированияТекста(Результат, ДополнительныеПараметры) Экспорт
    
    Если Результат <> Неопределено Тогда
        // Вместо прямого присвоения ТекущиеДанные.Комментарий = Результат
        // Мы используем механизм ОповеститьОВыборе
        // Это заставит платформу поместить значение в ТЕКУЩИЙ активный элемент
        Элементы.СписокТоваров.ТекущийЭлемент.ОповеститьОВыборе(Результат);
    КонецЕсли;
    
КонецПроцедуры

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

Способ 2. Ручное управление отменой через кэширование данных

Если по каким-то причинам метод с ОповеститьОВыборе вам не подходит (например, при сложном программном изменении нескольких полей сразу), можно воспользоваться механизмом ручного отката. Для этого нам понадобится событие таблицы ПриНачалеРедактирования и ПриОкончанииРедактирования.

Рассмотрим этот процесс по шагам:

  1. Создадим переменную в модуле формы для хранения «старого» состояния строки.
  2. В момент начала редактирования строки будем копировать данные текущей строки в эту переменную.
  3. Если пользователь нажимает отмену (что фиксируется в параметрах события завершения), мы вручную восстанавливаем данные.

Пример реализации:


&НаКлиенте
Перем КопияТекущейСтроки; // Переменная модуля формы

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

&НаКлиенте
Процедура СписокТоваровПриОкончанииРедактирования(Элемент, НоваяСтрока, ОтменаРедактирования)
    
    Если ОтменаРедактирования Тогда
        // Если пользователь нажал Esc или отменил ввод другим способом
        // Восстанавливаем данные из нашей копии
        ТекущиеДанные = Элементы.СписокТоваров.ТекущиеДанные;
        Для Каждого КлючИЗначение Из КопияТекущейСтроки Цикл
            ТекущиеДанные[КлючИЗначение.Ключ] = КлючИЗначение.Значение;
        КонецЦикла;
    КонецЕсли;
    
КонецПроцедуры

Этот метод более универсален, так как он позволяет программно менять ТекущиеДанные в любой момент, не заботясь о том, как именно вызвано окно ввода. Мы просто гарантируем, что при отмене редактирования всей строки (событие ПриОкончанииРедактирования с флагом ОтменаРедактирования = Истина) данные вернутся в исходное состояние.

Способ 3. Скрытая колонка для хранения состояния

Разберем еще один практический вариант, упомянутый в обсуждениях. Вы можете добавить в таблицу значений или табличную часть дополнительную колонку (реквизит), которую не будете выносить на форму. Назовем ее, например, ЗначениеДоРедактирования.

Логика работы в этом случае следующая:

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

Важные нюансы настройки элементов формы

Выясним некоторые технические детали, которые влияют на поведение поля ввода при программном заполнении:

  1. Режим редактирования колонки: В свойствах колонки таблицы есть свойство РежимРедактирования. Если установлено Вход в ячейку, то при программном присвоении фокус может «вылететь» из режима редактирования. Для работы с многострочными текстами часто удобнее использовать режим В отдельном окне.
  2. Обновление текста редактирования: У поля ввода есть свойство ОбновлениеТекстаРедактирования. Для корректного интерактивного отображения изменений рекомендуется устанавливать его в значение ПриИзменении.
  3. Событие ОбработкаВыбора: Помните, что если вы используете ОповеститьОВыборе, то данные сначала попадут в событие колонки ОбработкаВыбора. Если вы опишете этот обработчик и установите в нем СтандартнаяОбработка = Ложь, то автоматической подстановки значения не произойдет, и вам снова придется записывать данные в ТекущиеДанные вручную, что вернет вас к проблеме с отменой. Поэтому в ОбработкаВыбора лучше ничего не писать, если вы хотите стандартного поведения буфера.

Заключение

Проанализировав ситуацию, мы видим, что наиболее элегантным решением является использование штатного механизма ОповеститьОВыборе с предварительной установкой СтандартнаяОбработка = Ложь в событии НачалоВыбора. Это позволяет «обмануть» платформу, заставив её думать, что ввод сделал сам пользователь, и сохранить все преимущества стандартного интерфейса, включая отмену по Esc.

Если же логика ввода слишком сложна для стандартного механизма выбора, использование событий ПриНачалеРедактирования и ПриОкончанииРедактирования для ручного управления кэшем данных является проверенным и надежным профессиональным подходом.

← На главную