При разработке в 1С v7.7 программисты часто сталкиваются с ситуациями, когда один и тот же метод или функция ведут себя по-разному в зависимости от контекста, например, в модуле документа или в модуле формы обработки. Именно такая ситуация возникает с методом НазначитьТип(), который предназначен для динамического определения типа элемента диалога, изначально объявленного как "Неопределенный". Давайте подробно разберем, почему возникает эта проблема и как ее эффективно решить.
Представим, что у нас есть реквизит формы видПлатежа типа "Справочник.ВидыОпераций" и реквизит субконтоПлатежа типа "Неопределенный". Наша задача — динамически установить тип для субконтоПлатежа в зависимости от выбранного видПлатежа. Типичный сценарий, например, для выбора субконто по определенному счету.
Вы пытаетесь использовать следующий синтаксис:
НазначитьТип("субконтоПлатежа", видПлатежа.Счет.ВидСубконто(1));
И здесь мы сталкиваемся с интересным поведением 1С v7.7:
Процедура не обнаружена (НазначитьТип)
Почему так происходит? Выясним причину этого различия и найдем правильное решение.
Ключ к решению проблемы кроется в понимании контекста выполнения метода НазначитьТип(). В 1С v7.7 этот метод не является методом глобального контекста, доступным отовсюду напрямую. Вместо этого, он является методом контекста программного модуля формы. Это означает, что для его использования необходимо обращаться к нему через объект, представляющий саму форму.
Различия в контексте:
Модуль документа: Когда вы работаете в модуле документа, если реквизит (например, субконтоПлатежа) является реквизитом самого документа (а не только элементом диалога на форме, привязанным к нему), и ему в конфигураторе установлен тип "Неопределенный", то метод НазначитьТип() может быть вызван напрямую для этого реквизита или для элемента диалога, который к нему привязан, потому что контекст документа часто 'пересекается' с контекстом его формы в более упрощенном виде. Однако даже здесь более корректным является обращение через объект формы для элементов диалога.
Модуль формы обработки: В случае формы обработки или когда речь идет о реквизите, который существует только на форме (как элемент диалога), а не как реквизит базового объекта, к методу НазначитьТип() необходимо обращаться через атрибут Форма. Объект Форма представляет текущую форму и предоставляет доступ к ее свойствам и методам, включая методы, специфичные для элементов диалога.
Таким образом, когда система выдает "Процедура не обнаружена", это означает, что она не может найти метод НазначитьТип() в текущем неявном контексте. Мы должны явно указать, что этот метод относится к текущей форме.
На основе вышеизложенного, правильный синтаксис для вызова метода НазначитьТип() для реквизита, расположенного на форме (например, в форме обработки), будет выглядеть следующим образом:
Форма.ИмяРеквизитаФормы.НазначитьТип(ТипДанных);
Рассмотрим полный синтаксис метода НазначитьТип():
НазначитьТип(<ИмяРеквизита>, <ИмяТипа>, [<Длина>], [<Точность>])
<ИмяРеквизита>: Строковое выражение, содержащее наименование реквизита неопределенного типа, как он задан в конфигураторе. Внимание: это имя реквизита на форме, а не переменная в модуле.<ИмяТипа>: Строковое выражение, содержащее имя типа данных, которое назначается реквизиту. Например, 'Строка', 'Число', 'Справочник.Товары', 'Документ.РасходнаяНакладная'. При работе с субконто часто используется результат метода ВидСубконто().<Длина> (необязательный): Числовое выражение, указывающее допустимую длину значения для строкового или числового типа.<Точность> (необязательный): Числовое выражение, указывающее количество знаков после десятичной точки для числового типа.Важно отметить, что в 1С v7.7 метод НазначитьТип(), примененный к элементу диалога, который является реквизитом формы, вызывается через объект Форма, а затем через сам элемент диалога. Таким образом, правильный синтаксис для нашей задачи будет:
Форма.субконтоПлатежа.НазначитьТип(видПлатежа.Счет.ВидСубконто(1));
Именно такой подход позволил решить проблему, описанную в исходном сообщении. Теперь система корректно обнаруживает и вызывает метод НазначитьТип(), поскольку мы явно указываем, что работаем с элементом диалога текущей формы.
При работе с субконто, тип которого зависит от выбранного счета, метод ВидСубконто(НомерСубконто) является незаменимым. Этот метод применяется к объекту "Счет" и возвращает объект, который представляет тип субконто для указанного номера субконто данного счета. Например, видПлатежа.Счет.ВидСубконто(1) вернет тип для первого субконто выбранного счета из реквизита видПлатежа.
Полученное значение (объект типа субконто) затем передается в НазначитьТип() в качестве <ИмяТипа>. Это позволяет динамически настроить поле ввода субконтоПлатежа таким образом, чтобы оно позволяло выбирать только значения того справочника или документа, который определен как тип первого субконто для текущего счета.
После того как мы научились назначать тип реквизиту, возникает следующий логичный вопрос: а как, собственно, получить текущий тип реквизита на форме? Это может быть полезно для отладки или для создания универсальных механизмов, которые должны адаптироваться к текущему типу данных.
Для получения строкового обозначения типа данных значения реквизита формы в 1С v7.7 используются функции ТипЗначенияСтр(<Значение>) и ТипЗначения(<Значение>).
ТипЗначенияСтр(<Значение>): Эта функция возвращает строковое представление типа значения. Например, "Справочник", "Число", "Строка", "Документ" и т.д. Это удобно для отображения или логирования.
ТипЗначения(<Значение>): Эта функция возвращает числовое представление типа. Это позволяет использовать более детальную логику, например, для идентификации конкретного вида справочника или документа, используя оператор модуля % и сравнение с предопределенными значениями, известными из документации или методом эксперимента.
Пример получения типа для нашего реквизита субконтоПлатежа:
ТипВид = ТипЗначенияСтр(субконтоПлатежа) + ?(ТипЗначения(субконтоПлатежа)%14 > 3, "." + субконтоПлатежа.Вид(), "");
Давайте разберем этот код:
ТипЗначенияСтр(субконтоПлатежа): Получаем строковое название основного типа (например, "Справочник").?(<Условие>, <ЗначениеЕслиИстина>, <ЗначениеЕслиЛожь>): Это тернарный оператор.ТипЗначения(субконтоПлатежа)%14 > 3: Здесь используется числовое представление типа. Оператор %14 часто используется для определения категории объекта (например, справочник, документ). Конкретное значение > 3 (или другие числа) используется для идентификации сложных объектов, которые имеют подтипы (например, разные виды справочников или документов)."." + субконтоПлатежа.Вид(): Если условие истинно (то есть это сложный объект с подтипом), мы добавляем точку и строковое представление вида объекта (например, ".Товары" или ".Контрагенты"). Метод Вид(), примененный к объекту справочника или документа, возвращает его строковое имя, определенное в конфигураторе.Этот пример демонстрирует продвинутый способ получения полного строкового имени типа, который можно использовать для дальнейшей обработки или отображения. Например, если субконтоПлатежа назначен тип "Справочник.Товары", эта строка вернет "Справочник.Товары".
Разбирая проблему с НазначитьТип(), мы также можем рассмотреть другие аспекты и подходы, которые часто обсуждаются в контексте динамических типов в 1С v7.7:
Присвоение пустого значения нужного типа: Иногда возникает идея, что для изменения типа реквизита, объявленного как "Неопределенный", достаточно присвоить ему пустое значение нужного типа (например, субконтоПлатежа = СоздатьОбъект("Справочник.Товары");). Однако в 1С v7.7 этот подход, как правило, не приводит к изменению типа самого элемента диалога на форме. Элемент диалога останется "Неопределенным" и будет ожидать вызова НазначитьТип() для корректной работы выбора и отображения значений. Присвоение пустого значения лишь установит внутреннее значение переменной, но не настроит интерфейс. Этот подход более характерен для 1С 8.x, где присвоение пустого значения пустому реквизиту формы часто достаточно для ее настройки.
Использование внешних компонент: Для расширения функционала 1С v7.7 и упрощения работы с динамическими типами и интерфейсом, а также для обхода некоторых ограничений встроенного языка, часто применялись внешние компоненты, такие как 1CPP, FormEx или SQLite. Они позволяли реализовывать более сложные сценарии, которые были затруднительны или невозможны средствами встроенного языка. Однако в нашей задаче, как мы выяснили, хватает стандартных средств платформы.
Важность документации (СП): Как верно замечено в обсуждении, при возникновении подобных вопросов, первым шагом всегда должно быть обращение к встроенной справке 1С v7.7 (Синтакс-Помощник). Метод НазначитьТип() подробно описан в разделе "Атрибуты и методы контекста Модуля формы", где четко указано, что доступ к нему возможен только через атрибут Форма.
Мы выяснили, что метод НазначитьТип() в 1С v7.7 является мощным инструментом для динамической настройки элементов диалога типа "Неопределенный". Ключевым моментом является правильное обращение к нему через объект Форма, особенно при работе в модулях форм обработок, где неявный контекст может отличаться от модуля документа. Используя синтаксис Форма.ИмяРеквизита.НазначитьТип(...), мы обеспечиваем корректную работу приложения.
Кроме того, мы рассмотрели, как можно получить текущий тип реквизита с помощью функций ТипЗначенияСтр() и ТипЗначения(), что дополняет возможности по работе с динамическими типами в 1С v7.7. Эти знания являются фундаментальными для разработки гибких и адаптивных решений на этой платформе.
Помните, что хотя 1С v7.7 может показаться требовательной к синтаксису и контексту, глубокое понимание ее особенностей позволяет создавать эффективные и надежные программные решения.