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

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

При разработке интерфейсов на управляемых формах 1С часто возникает задача: при изменении значения в одной ячейке таблицы необходимо мгновенно проверить его корректность относительно других данных в той же самой строке. Например, пользователь вводит количество товара в колонку "Запросить", и система должна проверить, не превышает ли это число имеющийся "Остаток". Ситуация усложняется, если таких колонок "Запросить" много, и мы хотим использовать один универсальный обработчик для всех.

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

Разбор базовых механизмов доступа к данным строки

Прежде всего, проанализируем, как 1С работает с табличными частями на форме. Когда мы находимся внутри обработчика события ПриИзменении, нам нужно получить доступ к текущей строке. В управляемых формах для этого используется свойство расширения таблицы ТекущиеДанные. Важно понимать разницу: Элементы.ИмяВашейТаблицы — это визуальный объект на форме, а Элементы.ИмяВашейТаблицы.ТекущиеДанные — это структура (точнее, объект типа ДанныеФормыЭлементКоллекции), которая содержит значения всех реквизитов текущей строки.

Рассмотрим простейший пример, когда у нас есть фиксированная колонка. Чтобы обратиться к остатку в текущей строке, мы используем конструкцию:


ТекущаяСтрока = Элементы.ТабличнаяЧасть.ТекущиеДанные;
Если ТекущаяСтрока <> Неопределено Тогда
    Остаток = ТекущаяСтрока.Остаток;
КонецЕсли;

Обратите внимание на обязательную проверку на Неопределено. Если пользователь нажмет на пустую область таблицы, где нет строк, обращение к свойству ТекущиеДанные вызовет ошибку конфигурации.

Универсальное решение для нескольких колонок

Представим ситуацию: в таблице есть колонки Запросить1, Запросить2, Запросить3. Мы назначили им всем один и тот же обработчик ПриИзменении. Как внутри этого обработчика понять, какое именно поле было изменено? Для этого мы воспользуемся свойством элемента управления Имя.

Проанализируем шаги реализации универсального алгоритма:

  1. Получаем имя текущего элемента (колонки), который вызвал событие.
  2. Получаем доступ к данным текущей строки.
  3. Используем механизм динамического обращения к свойствам через квадратные скобки [].

Вот как это выглядит в коде:


&НаКлиенте
Процедура ТабличнаяЧастьЗапроситьПриИзменении(Элемент)
    
    // Получаем данные текущей строки
    ДанныеСтроки = Элементы.ТабличнаяЧасть.ТекущиеДанные;
    
    Если ДанныеСтроки = Неопределено Тогда
        Возврат;
    КонецЕсли;
    
    // Элемент — это параметр, который 1С автоматически передает в процедуру.
    // В нем содержится ссылка на поле формы, которое было изменено.
    ИмяРеквизита = Элемент.Имя;
    
    // Получаем введенное значение по имени колонки
    ВведенноеЗначение = ДанныеСтроки[ИмяРеквизита];
    
    // Сравниваем с остатком
    Если ВведенноеЗначение > ДанныеСтроки.Остаток Тогда
        Сообщить("Внимание! Запрошенное количество (" + ВведенноеЗначение + ") превышает остаток (" + ДанныеСтроки.Остаток + ")");
        // Здесь можно обнулить значение или вернуть старое
        ДанныеСтроки[ИмяРеквизита] = 0;
    КонецЕсли;
    
КонецПроцедуры

Решение проблемы несовпадения имен элементов и реквизитов

Часто программисты сталкиваются с тем, что код выше выдает ошибку "Поле объекта не обнаружено". Выясним причину: это происходит из-за того, что имя элемента на форме (например, ТабличнаяЧастьЗапросить1) не всегда совпадает с именем реквизита в данных (например, Запросить1). 1С часто добавляет префикс таблицы к имени поля при автоматической генерации формы.

В этом случае нам нужно либо переименовать элементы формы вручную, чтобы они совпадали с именами реквизитов, либо использовать свойство ПутьКДанным. Разберем второй, более надежный способ:


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

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

Важные нюансы и обработка ошибок

Проанализируем еще один важный момент: использование параметра Отказ. В событии ПриИзменении параметра Отказ не существует. Это уведомление о том, что данные уже записаны в память (в ДанныеФормы). Если вы хотите запретить пользователю переходить к другой ячейке при ошибке, вам следует использовать событие ПередОкончаниемРедактирования самой таблицы или Валидацию при сохранении всего документа.

Также стоит учитывать типы данных. Если в колонке Остаток может оказаться пустое значение или NULL (например, при левом соединении в запросе), прямое сравнение приведет к ошибке. Рекомендуем всегда проверять данные на заполненность или использовать приведение типов:


// Безопасное сравнение чисел
Если Число(ЗначениеЯчейки) > Число(ДанныеСтроки.Остаток) Тогда
    // Логика обработки
КонецЕсли;

Для визуального выделения ошибки лучше использовать объект СообщениеПользователю. Рассмотрим пример, как "привязать" ошибку к конкретной ячейке, чтобы она подсветилась пользователю:


Сообщение = Новый СообщениеПользователю;
Сообщение.Текст = "Количество не может быть больше остатка!";
Сообщение.Поле = Элемент.ПутьКДанным; // Указываем путь к конкретной ячейке
Сообщение.УстановитьДанные(Объект);
Сообщение.Сообщить();

Таким образом, мы разобрали комплексный подход к сравнению данных в строке таблицы. Используя ТекущиеДанные и динамическое обращение через квадратные скобки по ПутиКДанным, вы сможете создавать гибкие и надежные интерфейсы, которые корректно обрабатывают ввод пользователя даже в сложных многоколоночных таблицах.

← На главную