Почему табличная часть документа 1С самопроизвольно скроллируется вправо при изменении данных?

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

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

Анализируем исходную проблему

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

В ходе первичной диагностики мы с вами первым делом исключим самые очевидные причины, которые могли бы привести к такому поведению:

  1. Отключение ручного добавления строк: В нашем случае ручное добавление строк в документе отключено. Это исключает возможность того, что скроллирование связано с автоматическим позиционированием на новой строке.
  2. Скрытые колонки: Мы убедились, что в табличной части нет колонок со свойством Видимость = Ложь. Однако важно понимать, что "скрытые" могут означать также колонки, которые просто отскроллированы за пределы видимой области экрана.
  3. Уход фокуса с колонки: Была выдвинута гипотеза, что фокус может перемещаться на колонку, находящуюся вне видимой области. Однако отладка показала, что фокус фактически остается на той же колонке, где происходило изменение данных, что усложняет диагностику.

Ключевое наблюдение: Разница между реквизитами объекта и реквизитами формы

Давайте подробно рассмотрим, как удалось выявить истинную причину самопроизвольного скроллирования. Отладка и детальный анализ показали, что поведение табличной части напрямую зависит от того, какой тип реквизита изменяется программно — реквизит объекта или реквизит формы.

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

  1. Колонка А: Реквизит табличной части документа (объекта). Значение в ней интерактивно изменяется пользователем.
  2. Колонка Б: Реквизит табличной части документа (объекта). Ее значение пересчитывается программно при изменении колонки А.
  3. Колонка В: Реквизит табличной части формы. Ее значение также пересчитывается программно при изменении колонки А.

Для пересчета значений колонок Б и В используется схожий подход, ориентированный на работу с текущими данными формы:


ТекущиеДанные = Элементы.НоменклатурныйПлан.ТекущиеДанные;
// Предположим, что здесь изменяется ТекущиеДанные.РеквизитА
// и на основе этого нового значения пересчитываются РеквизитБ и РеквизитВ
// Примеры изменения Б и В (как описано в проблеме):
// ТекущиеДанные.РеквизитБ = НовоеРассчитанноеЗначениеДляБ;
// ТекущиеДанные.РеквизитВ = НовоеРассчитанноеЗначениеДляВ;

Внимание, ключевое отличие! Именно в этом месте мы обнаружили разницу в поведении:

Это наблюдение является критически важным. Оно указывает на то, что платформа 1С по-разному обрабатывает обновление данных, которые напрямую связаны с объектом базы данных, и данных, которые существуют только на стороне клиента (реквизиты формы).

Потенциальные причины и механизмы

Почему же возникает такая "петрушка"? Проанализируем возможные механизмы, приводящие к такому поведению:

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

Решения проблемы самопроизвольного скроллирования

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

  1. Изменение данных на сервере

    Это наиболее надежный и рекомендуемый подход. Если изменение данных в табличной части приводит к пересчету других значений, которые также являются реквизитами объекта, или если требуется изменить реквизит объекта, то выполнять эти действия следует на сервере.

    Принцип работы:

    Мы инициируем изменение на клиенте (например, при окончании редактирования ячейки). Затем вызываем серверный метод, который получает объект документа, находит нужную строку табличной части, обновляет все необходимые реквизиты объекта (включая расчетные поля), а затем возвращает обновленный объект формы на клиент. Платформа 1С автоматически корректно обновит отображение данных на форме, как правило, без нежелательного скроллирования, поскольку изменения происходят через объект, а не напрямую через реквизиты формы.

    Рассмотрим подробнее на примере:

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

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

  2. Передача данных через реквизит формы и методы обновления

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

    Для принудительного обновления отображения данных на форме 1С, включая табличные части, существуют следующие методы:

    • ОбновитьОтображениеДанных(): Этот метод принудительно обновляет содержимое элементов управления формы. Он полезен, когда значения реквизитов формы изменяются программно вне явного контекста взаимодействия с элементом управления, и форма при этом отображается на экране.
    • Обновить(): Метод Обновить(), примененный к элементу табличной части (например, Элементы.НоменклатурныйПлан.Обновить()), обновляет данные в таблице. Он может помочь, но не всегда гарантирует предотвращение скроллирования, так как его действие может быть менее полным, чем внутренние механизмы платформы при изменении реквизитов формы.
    • ОповеститьОбИзменении(): Если в табличной части отображается ссылка (например, на другой объект), и эта ссылка меняется программно, а вместе с ней необходимо обновить ее наименование, то может помочь вызов ОповеститьОбИзменении(). Этот метод позволяет оповестить форму о том, что данные, на которые ссылаются элементы, могли измениться, и требуется их перерисовка.

    Важное замечание: Применение этих методов может помочь, но не дает 100% гарантии полного отсутствия скроллирования. Платформа все равно может решить, что ей необходимо "показать" обновленные данные, что может привести к нежелательной прокрутке. Поэтому, если возможно, всегда стремитесь работать с реквизитами объекта на сервере.

  3. Программное управление прокруткой (для Табличного Документа, не Табличной Части формы)

    Стоит провести четкое различие между элементом управления "Табличная часть" формы и элементом "Табличный документ". Проблема в нашей теме относится к "Табличной части" формы. Тем не менее, для "Табличного документа" (который чаще используется для вывода печатных форм или сложных отчетов), существует возможность программного управления прокруткой через свойство ТекущаяОбласть.

    Например, чтобы прокрутить табличный документ к началу, мы могли бы использовать следующий код:

    
    // Это относится к элементу формы типа "Поле табличного документа",
    // а не к табличной части документа.
    ЭлементыФормы.ПолеТабличногоДокумента1.ТекущаяОбласть = ЭлементыФормы.ПолеТабличногоДокумента1.Область("R1C1");
    

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

  4. Оптимизация формы и колонок

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

    Мы рекомендуем:

    • Пересмотреть ширину колонок: Убедитесь, что каждая колонка имеет оптимальную ширину, не занимающую лишнего места.
    • Использовать свойство АвтоРазмер: Это свойство для колонок табличной части позволяет платформе автоматически подстраивать их ширину под содержимое.
    • Расположение элементов: Проанализируйте расположение других элементов на форме. Возможно, их можно сгруппировать или разместить таким образом, чтобы дать больше пространства табличной части.
    • Минимизация колонок: Если возможно, рассмотрите возможность уменьшения общего количества колонок, отображаемых по умолчанию, или использования динамического изменения видимости колонок в зависимости от контекста.

    Минимизация необходимости в ручной горизонтальной прокрутке сама по себе может снизить вероятность возникновения "глюков" с автоматическим скроллированием. Для быстрой проверки и корректировки свойств элементов интерфейса без изменения конфигурации можно использовать обработку для редактирования свойств элементов форм в режиме предприятия.

  5. Проверка версии платформы

    В некоторых, более редких случаях, нежелательное скроллирование или другие аномалии в отображении управляемых форм могут быть вызваны ошибками в самой платформе 1С. Известны случаи, когда в старых версиях платформы табличные части с большим количеством колонок "выезжали" за пределы окна. Мы рекомендуем:

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

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

← На главную