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