При интерактивной работе с табличным полем в обычном приложении 1С разработчики часто сталкиваются с ситуацией: после перетаскивания значения фон ячейки-приемника успешно окрашивается, однако при следующем действии (перетаскивании другого значения, клике мышью или прокрутке) предыдущая ячейка вновь возвращается к стандартному беглому цвету. Окрашенной остается только последняя измененная строка.
Разберем архитектурные причины такого поведения платформы 1С:Предприятие и пошагово реализуем правильный механизм долговременного сохранения цвета ячеек.
Табличное поле в обычном приложении функционирует по принципу виртуального списка. Оно не хранит внутри себя визуальное состояние каждой ячейки или строки между перерисовками. Как только интерфейс требует обновления (например, завершилась операция перетаскивания Drag and Drop, сменился фокус строки или сработал скроллинг), платформа генерирует события отрисовки данных:
ПриВыводеСтроки — вызывается последовательно для каждой видимой строки;ПриПолученииДанных — вызывается пакетом для массива оформлений строк, что работает значительно быстрее.Свойства визуального оформления, такие как ОформлениеСтроки.Ячейки[ИмяКолонки].ЦветФона или шрифт, являются временным состоянием отрисовки конкретного кадра. Если попытаться изменить цвет ячейки один раз в обработчике события мыши или перетаскивания, при следующем же обновлении экрана табличное поле запросит данные заново. Если в событии отрисовки нет четкой команды окрасить конкретную ячейку на основании сохраненных данных, платформа применит параметры оформления по умолчанию, и ячейка станет белой.
Главное правило: табличное поле отображает только то, что сохранено в источнике данных или специальных коллекциях формы на момент вызова обработчиков отрисовки.
Рассмотрим два надежных способа сохранения информации о цвете ячеек.
Если источником данных для табличного поля является объект ТаблицаЗначений, простейший и самый надежный путь — добавить в нее служебные колонки для фиксации состояния ячеек.
Разберем этот вариант поэтапно:
Булево (например, с постфиксом _Окрашена) или колонку для хранения цвета.Перетаскивание переносим данные и устанавливаем флаг модификации в соответствующей строке таблицы.ПриПолученииДанных считываем флаг и задаем ЦветФона.ОбновитьСтроки().Посмотрим на пример программной реализации логики перетаскивания:
Процедура ТабличноеПолеПеретаскивание(Элемент, ПараметрыПеретаскивания, СтандартнаяОбработка, Строка, Поле)
СтандартнаяОбработка = Ложь;
// Получаем переносимое значение и целевую строку
Если Строка = Неопределено Или Поле = Неопределено Тогда
Возврат;
КонецЕсли;
ИмяКолонки = Поле.Имя;
// Переносим значение в ячейку-приемник
Строка[ИмяКолонки] = ПараметрыПеретаскивания.Значение;
// Фиксируем признак окраски в служебной колонке таблицы
ИмяСлужебнойКолонки = ИмяКолонки + "_Окрашена";
Строка[ИмяСлужебнойКолонки] = Истина;
// Инициируем точечную перерисовку только измененной строки
МассивСтрок = Новый Массив;
МассивСтрок.Добавить(Строка);
Элемент.ОбновитьСтроки(МассивСтрок);
КонецПроцедуры
Теперь настроим обработчик пакетной отрисовки ПриПолученииДанных. Использование именно этого события вместо ПриВыводеСтроки обеспечивает оптимальное быстродействие при большом количестве строк:
Процедура ТабличноеПолеПриПолученииДанных(Элемент, ОформленияСтрок)
ЦветВыделения = Новый Цвет(175, 238, 238); // Цвет морской волны для подсветки
Для Каждого ОформлениеСтроки Из ОформленияСтрок Цикл
ДанныеСтроки = ОформлениеСтроки.ДанныеСтроки;
// Проверяем служебную колонку для нужной ячейки
Если ДанныеСтроки.Колонка1_Окрашена = Истина Тогда
ОформлениеСтроки.Ячейки.Колонка1.ЦветФона = ЦветВыделения;
КонецЕсли;
Если ДанныеСтроки.Колонка2_Окрашена = Истина Тогда
ОформлениеСтроки.Ячейки.Колонка2.ЦветФона = ЦветВыделения;
КонецЕсли;
КонецЦикла;
КонецПроцедуры
Обратите внимание: служебные колонки не обязательно отображать пользователю — достаточно не добавлять их в состав колонок самого элемента управления ТабличноеПоле на форме.
Бывают ситуации, когда менять состав колонок исходной таблицы значений нельзя или нежелательно. В этом случае мы можем хранить координаты окрашенных ячеек в переменной формы типа Соответствие.
Разберем по шагам алгоритм с внешней коллекцией:
мОкрашенныеЯчейки. При открытии формы инициализируем ее объектом Новый Соответствие.СтрокаТаблицыЗначений (пока таблица не очищается и не пересоздается, ссылка на строку в памяти стабильна), а значением — Структура или Массив с именами колонок.Проанализируем пример реализации:
// В начале модуля формы
Перем мОкрашенныеЯчейки;
Процедура ПриОткрытии()
мОкрашенныеЯчейки = Новый Соответствие;
КонецПроцедуры
Процедура ТабличноеПолеПеретаскивание(Элемент, ПараметрыПеретаскивания, СтандартнаяОбработка, Строка, Поле)
СтандартнаяОбработка = Ложь;
Если Строка = Неопределено Или Поле = Неопределено Тогда
Возврат;
КонецЕсли;
ИмяКолонки = Поле.Имя;
Строка[ИмяКолонки] = ПараметрыПеретаскивания.Значение;
// Получаем текущий список окрашенных колонок для данной строки
СписокКолонок = мОкрашенныеЯчейки[Строка];
Если СписокКолонок = Неопределено Тогда
СписокКолонок = Новый Соответствие;
мОкрашенныеЯчейки.Вставить(Строка, СписокКолонок);
КонецЕсли;
СписокКолонок.Вставить(ИмяКолонки, Истина);
// Обновляем строку на клиенте
МассивСтрок = Новый Массив;
МассивСтрок.Добавить(Строка);
Элемент.ОбновитьСтроки(МассивСтрок);
КонецПроцедуры
Процедура ТабличноеПолеПриПолученииДанных(Элемент, ОформленияСтрок)
ЦветВыделения = Новый Цвет(255, 235, 156);
Для Каждого ОформлениеСтроки Из ОформленияСтрок Цикл
СписокКолонок = мОкрашенныеЯчейки[ОформлениеСтроки.ДанныеСтроки];
Если СписокКолонок <> Неопределено Тогда
Для Каждого КлючИЗначение Из СписокКолонок Цикл
ОформлениеСтроки.Ячейки[КлючИЗначение.Ключ].ЦветФона = ЦветВыделения;
КонецЦикла;
КонецЕсли;
КонецЦикла;
КонецПроцедуры
ПриПолученииДанных вызывается реже и имеет приоритет при передаче пачки оформлений на клиента. Использование двух событий сразу приведет к двойной нагрузке на интерфейс.Обновить() без параметров) при перетаскивании единичных ячеек. Метод ОбновитьСтроки() с передачей массива целевых строк вызывает обработчик отрисовки только для них, что устраняет мерцание интерфейса.Таким образом, для устойчивого окрашивания ячеек в обычном приложении 1С необходимо разделить визуализацию и хранение состояния: сохранять факт изменения в таблице значений или коллекции и применять оформление строго внутри обработчиков отрисовки строк.