Как программно управлять текущей строкой динамического списка и выделением дат в календаре?

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

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

Установка текущей строки в динамическом списке

Проанализируем первую задачу: как сделать так, чтобы динамический список автоматически «прыгнул» на нужную нам позицию? Многие начинающие разработчики пытаются найти номер строки, как в обычном массиве или таблице значений, но в динамическом списке этот подход не работает, так как данные подгружаются порциями.

Выясним причину: основным идентификатором строки в динамическом списке (если у него указана основная таблица) является ссылка на объект базы данных (например, на справочник или документ). Рассмотрим, как это реализовать на практике. Если нам известна ссылка на конкретный элемент, мы можем напрямую передать её свойству ТекущаяСтрока соответствующего элемента формы.

Посмотрим на пример кода:


// Предположим, у нас есть ссылка на номенклатуру, полученная запросом или переданная в параметрах
СсылкаНаОбъект = Справочники.Номенклатура.НайтиПоНаименованию("Нужный товар");

// Устанавливаем фокус на эту строку в элементе формы "Список"
Элементы.Список.ТекущаяСтрока = СсылкаНаОбъект;

Важно помнить о нескольких нюансах:

  1. Соответствие отбору: Если в динамическом списке установлен отбор (например, по группе или по конкретному реквизиту), и искомый объект под этот отбор не попадает, фокус на строку не перейдет. Платформа просто проигнорирует команду.
  2. Иерархия и группировки: Если в списке включена группировка, ключом строки может выступать не просто ссылка, а специальная структура. Однако для простых списков без группировок использования ссылки достаточно.
  3. Метод «ОтобразитьСтроку»: Чтобы гарантировать, что пользователь увидит строку (она окажется в видимой области), рекомендуется использовать метод Элементы.Список.ОтобразитьСтроку(ИдентификаторСтроки).

Программное выделение даты в поле календаря

Перейдем ко второму вопросу: как программно заставить календарь «выбрать» нужную дату? В управляемом интерфейсе 1С поле календаря имеет специальное свойство — коллекцию ВыделенныеДаты. Рассмотрим, как с ней работать.

Если нам нужно установить курсор на конкретную дату, мы должны сначала очистить текущее выделение, а затем добавить туда наше значение. Разберем по шагам:


// Определим дату, которую хотим выделить
НужнаяДата = НачалоДня(ТекущаяДата());

// Очищаем старые выделения, если режим выделения позволяет выбирать несколько дат
Элементы.Календарь.ВыделенныеДаты.Очистить();

// Добавляем новую дату в коллекцию выделенных
Элементы.Календарь.ВыделенныеДаты.Добавить(НужнаяДата);

Этот способ позволяет визуально переместить «рамку» выбора на нужный день. Однако, если эта дата находится в другом месяце или году, пользователь может её не увидеть сразу, так как календарь не прокрутится автоматически.

Решение проблемы с прокруткой календаря к дате

Проанализируем ситуацию: что делать, если выделенная дата находится вне текущей области видимости? В обсуждениях на форумах часто встречаются «костыли» с переопределением периодов отображения, но существует более элегантный способ — использование свойства ОтображаемаяДата.

Чтобы календарь автоматически прокрутился к нужному месяцу, выполним следующее:


// Устанавливаем дату, месяц которой должен быть показан пользователю
Элементы.Календарь.ОтображаемаяДата = НужнаяДата;

Этот метод является стандартным и наиболее надежным для позиционирования визуальной сетки календаря.

Расширенное оформление дат в календаре

Иногда простого выделения «рамкой» недостаточно. Например, нам нужно подсветить цветом все даты, на которые запланированы события. Для этого существует событие ПриВыводеПериода. Проанализируем, как оно работает.

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

Рассмотрим пример реализации:


&НаКлиенте
Процедура КалендарьПриВыводеПериода(Элемент, ОформлениеПериода)
    
    Для Каждого ТекДата Из ОформлениеПериода.Даты Цикл
        // Проверяем условие, например, совпадение с датой из нашего списка событий
        Если ТекДата.Дата = ДатаВажногоСобытия Тогда
            // Устанавливаем визуальные свойства
            ТекДата.ЦветФона = Новый Цвет(255, 200, 200); // Светло-красный
            ТекДата.ЦветТекста = Новый Цвет(0, 0, 0);      // Черный
            ТекДата.Шрифт = Новый Шрифт(,,Истина);       // Жирный
        КонецЕсли;
    КонецЦикла;
    
КонецПроцедуры

Важное замечание по производительности: Поскольку процедура ПриВыводеПериода вызывается очень часто (при каждом скролле, изменении размера окна и т.д.), внутри неё категорически нельзя выполнять запросы к базе данных. Подготовьте массив или соответствие дат заранее на сервере и храните его в реквизите формы, а в процедуре оформления просто сверяйтесь с этим готовым набором данных.

Синхронизация календаря и динамического списка

Чаще всего эти механизмы объединяются: пользователь щелкает по дате в календаре, а в динамическом списке отображаются записи только за этот день. Разберем, как это реализовать.

  1. Создадим обработчик события ПриИзменении для поля календаря.
  2. Внутри обработчика получим выбранную дату из коллекции Элементы.Календарь.ВыделенныеДаты.
  3. Установим отбор в динамическом списке, используя КомпоновщикНастроек.

Посмотрим на пример кода установки отбора:


&НаКлиенте
Процедура КалендарьПриИзменении(Элемент)
    
    Если Элементы.Календарь.ВыделенныеДаты.Количество() > 0 Тогда
        ВыбраннаяДата = Элементы.Календарь.ВыделенныеДаты[0];
        УстановитьФильтрСписка(ВыбраннаяДата);
    КонецЕсли;
    
КонецПроцедуры

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

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

← На главную