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