Основы работы с объектной моделью IS-Builder

10 6

 

Это четвертая статья из цикла, посвященного основам работы на ISBL. В этой статье будут рассмотрены основы работы с объектами в ISBL.

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

Работа с объектами, принципы обращения к методам и свойствам

Объектом в ISBL считается любой элемент системы, с которым прикладной разработчик так или иначе может взаимодействовать – электронный документ, задача, справочник и т.д. У каждого объекта есть методы для выполнения каких-либо действий (например, сохранение электронного документа) и свойства, содержащие данные об объекте.

Объектная модель IS-Builder – иерархия типов объектов  платформы IS-Builder.

Объект можно получить следующими способами:

- С помощью специальных системных функций, например, CreateStringList(), предназначенной для создания списка строк.

- С помощью других объектов, например объектов-фабрик, работа с которыми будет рассмотрена позже в этой статье. 

Свойство объекта - это способ доступа к данным об объекте. Свойствами объекта, например IEDocument, являются наименование, автор и т.п.

Метод объекта - это операция над объектом. Например, старт задачи, экспорт документа с блокировкой и т.п.

Для обращения к свойствам и методам объектов используется следующий синтаксис:

<переменная-объект>.<имя свойства>([<параметры свойства>])

<переменная-объект>.<имя метода>([<параметры метода>])

Здесь [] указывают на то, что различные методы или свойства могут вызываться как с параметрами, так и без них.

  // Получение объекта через системную функцию
  // Создадим объект список строк (IStringList) 
  StringList = CreateStringList()
  // Установим значение свойства Delimiter(Разделитель)
  // Строки в списке будут разделяться указанным разделителем
  StringList.Delimiter = ';'
  // Добавим строки и выведем текст на экран
  StringList.Add(‘Пример работы с объектами’)
  StringList.Add(‘Эта строка будет после “;”.’)
  // Выведем текст на экран
  EditText(StringList.DelimitedText)

Начиная с DIRECTUM 5.1 функционал редактора вычислений расширен. Для упрощения разработки на ISBL добавлены подсказки по объектной модели:

  • по методам и свойствам интерфейсов,
  • по реквизитам справочников и документов,
  • по параметрам методов,
  • по типам переменных (интерфейсные типы, типы справочников, типы карточек документов).

В следующем примере мы получим объект IEDocument, изменим его имя и сохраним:

  // Получение объекта через объект-фабрику
  // ИД документа
  EDocID = '35123'
  // С помощью метода GetObjectByID получим объект
  EDocument = EDocuments.GetObjectByID(EDocID)
  // Изменим наименование документа
  EDocument.Requisites('ISBEDocName').Value = ‘Новое наименование’
  // Вызовем метод Save - сохранение документа 
  EDocument.Save()

ISBL поддерживает работу как с внутренними объектами - объектная модель IS-Builder, так и с внешними, например, объектная модель Microsoft Office.

Наследование

Наследование - это механизм, реализующий возможность использования объектом-наследником функциональности, методов и свойств родительского объекта. 

Рассмотрим примеры работы наследования для объекта ITask. Общая схема для объекта типа ITask выглядит так:

IObject <- IEdmsObject <- ICustomWork <- ITask, где "<-" указывает на родительский объект.

Используя механизм наследования, для объекта ITask есть возможность вызвать любые методы или обратиться к любым свойства родительского объекта. Например, можно вызвать метод Save(), определенный для родительского объекта типа IObject, который сохранит изменения набора данных.

Вызываемые родительские методы или свойства, работают в контексте  объекта-наследника. Метод GetObjectByID фабрики задач возвращает задачу, объект ITask,а при вызове GetObjectByIDу фабрики папок, IFolderFactory, мы получим папку, объект IFolder.

Метод GetObjectByID фабрики задач и фабрики папок наследуется от объекта IFactory. Из справки можно узнать, что IFactory.GetObjectByID возвращает объект IObject, это означает, что наследники объекта IFactory вернут объекты-наследники IObject.

Работа с фабриками

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

  1. Через свойства объекта IApplication, при обращении к объектной модели IS-Builderизвне;
  2. Через предопределенные переменные: References, Tasks и т.д., доступные внутри вычислений на ISBL.
  3. Через свойство IObject – Factory, для получения фабрики по объекту.

Фабрики позволяют выполнять:

- Создание и удаление объектов.

- Получение доступа к объектам.

- Выполнение характерных для данного типа объекта действий и т.д. Например «создать из файла» для фабрики документов или «очистить время напоминания» для фабрики задач.

  // Создать новую задачу
  Task = Tasks.CreateNew()
  // Установить тему задачи
  Task.Subject = 'Тестовая задача.'
  // Получим имя текущего пользователя
  AuthorName = Application.Connection.UserName
  // Получим объект IUser по имени текущего пользователя
  Author = ServiceFactory.GetUserByName(AuthorName)
  // Установим автора задачи
  Task.Author  = Author.Code
  // Создадим задание (этап маршрута) самому себе
  RouteStep = Tasks.CreateRouteStep(1; Author; jkJob; Today(); ""; "")
  // Добавить задание в маршрут
  Task.Route.Add(RouteStep)
  // Старт задачи
  Task.Start()

В приведенном выше примере предопределенная переменная Tasks - хранит фабрику задач ITaskFactoryServiceFactory - фабрику служебных объектов IServiceFactory.

Метод CreateRouteStep используется для создания этапа маршрута, поэтому использовать его имеет смысл только при работе с объектами ITask – для добавления нового этапа.

Пример работы с объектом IEDocument 

IEDocument - объект, который предназначен для работы с электронными документами.  

Работа с методами и свойствами

Рассмотрим пример, в котором запросим у пользователя ID документа,  установим стадию жизненного цикла документа в "Устаревший":

  // Диалог запроса ID документа
  EDocumentID = InputDialog('ИД'; ''; 'Число'; 'Введите ИД документа: ')
  // Получить объект по заданному ИД
  EDocument = EDocuments.GetObjectByID(EDocumentID)
  // Установить стадию жизненного цикла в "Устаревший"
  EDocument.SetLifeCycleStageByName("Obsolete")

И схожий пример, чтобы заблокировать документ:

  // Диалог запроса ID документа
  EDocumentID = InputDialog('ИД'; ''; 'Число'; 'Введите ИД документа: ')
  // Получить объект по заданному ИД
  EDocument = EDocuments.GetObjectByID(EDocumentID)
  MBResult = MessageBox(INFORMATION_CAPTION; 
    'Заблокировать документ?'; 'Да|Нет'; 'Нет'; 'Нет') 
  if MBResult == 'Да'
    // Заблокировать документ
    EDocument.Lock
    // Сообщение о блокировке 
    ShowMessage("Документ " & EDocument.Name & " заблокирован.")
  endif

Работа с реквизитами

Следующий пример выводит список имен и значений всех реквизитов объекта:

  // Получим документ
  EDoc = EDocuments.GetObjectByID(EDocID)
  // Список строк, в который будем записывать информацию о реквизитах
  RequisiteList= CreateStringList()
  // Разделитель между строками – знак переноса строки, CR
  RequisiteList.Delimiter = CR
  Index = 0
  // Пройдемся по всем реквизитам
  while Index < EDoc.RequisiteCount
    RequisiteList.Add(EDoc.RequisiteByIndex(Index).Name)
    RequisiteList.Add(EDoc.RequisiteByIndex(Index).AsString)
    RequisiteList.Add("----------") 
    Index = Index + 1
  endwhile
  EditText(RequisiteList.DelimitedText)

В этом примере, было использовано свойство RequisiteCount объекта IObject - оно содержит количество реквизитов объекта, а метод IObject.RequisiteByIndex() - по заданному индексу возвращает объект реквизит IRequisite. Этот способ получения объекта-реквизита IRequisite удобен, если мы хотим получить различную информацию о всех реквизитах объекта, но на практике чаще встречается задача получить информацию о реквизите по имени реквизита:

  // Получим значение реквизита и выведем в сообщении
  // Value, свойство объекта IRequisite, хранит значение реквизита
  ShowMessage(EDoc.Requisites('ISBEDocName').Value)
  ShowMessage(EDoc.ИД)

Для этого используется свойство IObject.Requisites(<Имя реквизита>), которое возвращает объект IRequisite по его имени.

В вычислениях на ISBL есть возможность обратиться напрямую к значению реквизита указав его имя после точки, например EDoc.ИД– вернет ИД документа. Запись EDoc.ИД эквивалентна EDoc.Requisites(“ИД”).Value

Также при работе с реквизитами, используйте свойство IObject.RequisiteValues - список типа IList, который содержит набор пар <имя реквизита> и <значение реквизита>.

Работа с детальным разделом

Детальные разделы- это объекты типа IDataSet, набор данных, представляющий собой совокупность записей (по аналогии со справочником, который является схожим типом объекта). Таким образом, детальные разделы - это "таблицы внутри записей".

У большинства объектов, например у IEDocument или ITask, в системе есть детальные разделы. Для получения детального раздела нужно вызвать метод DetailDataSet() объекта IObject. Детальные разделы нумеруются с 1 по 6. Чтобы проверить, существует ли детальный раздел у объекта, нужно вызвать метод DetailExists() объекта IObject и передать ему номер раздела в качестве параметра.

Рассмотрим пример работы с детальным разделом:

  // Диалог запроса ID документа
  DialogResult = InputDialog('ИД|Пользователь'; ''; 'Число|Аналитика:ПОЛ'; 
    'Введите ИД документа и выберите пользователя: ')
  // Получить результаты выполнения диалога
  EDocumentID = SubString(DialogResult; "|"; 1)
  UserCode = SubString(DialogResult; "|"; 2)
  User = ServiceFactory.GetUserByCode(UserCode)
  EDocument = EDocuments.GetObjectById(EDocumentID)
  // Получить детальный раздел 1 для документа,
  // который содержит информацию о правах доступа на электронный документ.
  // Более подробное описание можно найти в справочной системе, в книге
  // «Объектная модель DIRECTUM», в разделе «Реквизиты объектов DIRECTUM».
  EDocumentDDS = EDocument.DetailDataSet(1)
  AccessData = CreateStringList()
  AccessData.Delimiter = CR
  // Определить, есть ли ИД указанного пользователя в детальном разделе
  if EDocumentDDS.Locate('ISBEDocAccountID'; User.ID)
    ShowMessage('У пользователя ' & User.FullName & ' вид доступа "' & 
      EDocumentDDS.Requisites('ISBEDocAccessType').Value & '" для указанного документа!')  
  endif
  AccessData.Add("Список ИД пользователей или групп, имеющих права на изменение документа:")
  // Перейти на первую запись
  EDocumentDDS.First()
  // Пока запись не последняя
  while not EDocumentDDS.EOF
    if EDocumentDDS.Requisites('ISBEDocAccessType').Value == 'Изменение'
      AccessData.Add(EDocumentDDS.Requisites('ISBEDocAccountID').Value)
    endif
    // Перейти к следующей записи 
    EDocumentDDS.Next()
  endwhile
  EditText(AccessData.DelimitedText)

Работа с объектами типа IReference

Как уже упоминалось ранее, IDataSet - это объект, представляющий собой набор данных, а также методы и свойства для работы с ним. Работа с IReference, наследником IComponent, похожа на работу с IDataSet.

Набор данных IReference - это список записей. У каждой записи есть набор реквизитов, которые устанавливаются в разделе "Карточка" справочника. При работе с IReference нужно учитывать, что одна запись всегда является текущей. Рассмотрим работу с IReference более подробно:

  1. Получим объект IReference через метод GetComponent() фабрики IReferenceFactory через предопределенную переменную References.
  2. Откроем набор данных - вызовем метода Open() объекта IComponent. Перед работой с набором данных IReference его обязательно нужно открывать.
  3. Установим первую запись набора данных – текущей. Это можно сделать вызовом метода First() объекта IComponent.
  4. Найдем работника с фамилией именем и отчеством «Иванов Иван Иванович». Для этого воспользуемся циклом while, где в качестве условия укажем свойство IComponent.EOF «End of file». Его значение истинно, когда справочник пустой или достигнут его конец.
  5. Для перемещения по записям справочника, нужно использовать метод IComponent.Next(). Метод делает текущей следующую запись набора данных.
  6. Откроем текущую запись – вызовем метод OpenRecord() объекта IComponent, который откроет для чтения и изменения текущую запись.
  7. Изменим реквизит «Дополнение3» - «Табельный номер» в справочнике Работники для текущей записи. Воспользуемся свойством объекта IObject Requisites, которое возвращает объект IRequisite по указанному имени.
  8. Сохраним изменения – вызовем метод Save() объекта IObject.
  9. Закроем текущую запись – вызовем метод CloseRecord() объекта IComponent. Открытой может быть только одна запись, поэтому после работы открытую запись нужно всегда закрывать.
  10. Закроем набор данных после работы – вызовем метод Close() объекта IObject.
  // Получим объект IReference
  WorkerRef = References.ReferenceFactory('РАБ').GetComponent
  // Открыть набор данных справочника
  WorkerRef.Open()
  // Перейти к первой записи
  WorkerRef.First()
  // Выполнять, пока не конец справочника
  while not WorkerRef.EOF
    if WorkerRef.Requisites(“Дополнение”).Value == ‘Иванов Иван Иванович’
      // Открыть запись
      WorkerRef.OpenRecord()
      // Установить табельный номер
      WorkerRef.Requisites('Дополнение3').Value = "123"
      // Сохранить изменения
      WorkerRef.Save()
      // Закрыть запись
      WorkerRef.CloseRecord()
      // Если запись нашли, перейдем к последней записи
      // и выйдем из цикла
      WorkerRef.Last() 
   endif
  endwhile
  // Закрыть набор данных справочника
  WorkerRef.Close()

Каждая запись может иметь несколько детальных разделов ("табличная часть" карточки справочника), которые имеют тип IDataSet. Записи детальных разделов, однако, не могу иметь своих детальных разделов.

Рассмотрим пример работы с детальным разделом объектом IReference – добавим новую запись в справочник «Журналы регистрации»:

  // Получить объект IReference для указанного справочника 
  Reference = References.ReferenceFactory('ГДЛ').GetComponent
  // Открыть набор данных
  Reference.Open
  // Добавить запись
  Reference.Append
  // Открыть запись
  Reference.OpenRecord
  // Заполним реквизиты
  Reference.Requisites("Содержание").Value = "Тестовый журнал."
  Reference.Requisites("МестоРег").Value = "1"
  // Получим объект IDataSet детального раздела
  ReferenceDDS = Reference.DetailDataSet(1)
  // Добавим запись в детальный раздел
  ReferenceDDS.Append
  // Изменим реквизит детального раздела
  ReferenceDDS.Requisites('СтрокаТ').Value = "123"
  MBSaveResult = MessageBox(ATTENTION_CAPTION; 'Сохранить?'; 'Да|Нет'; 'Нет'; 'Нет')
  if MBSaveResult == 'Да'
    // Сохранить изменения
    Reference.Save
  else
    // Отменить изменения
    Reference.Cancel
  endif
  Reference.CloseRecord
  Reference.Close

 

Marina Kobzar

Скажите, пожалуйста, как  сделать реквизит в детальном разделе  readonly?

Денис Баранов

Двойной клик на таблице в редакторе формы и потом:

Marina Kobzar

 

Извините за некорректный вопрос, как программно закрыть поля для редактирования при наступлении некоторого события, например:если  поле "Признак" принимает значение "Да", то поле "Дата" закрыто для редактирования.(оба реквизита таблицы 1. )

Александр Павлов
//колонка только для просмотра
if  not VarIsNull(Object.Form.Controls.FindControl("STcxGrid1"))              
      Grid = Object.Form.Controls.FindControl("STcxGrid1")               
      ReqColumn = Grid.FindColumnByRequisiteName("ISBVersionAuthor")
      if not VarIsNull(ReqColumn)
        ReqColumn.ReadOnly = TRUE
      endif
endif             
Денис Баранов
Руслан Хасанов
По моему в коде не хватает инструкции WorkerRef.next() 
Без нее приложение уходит в бесконечный цикл.

  
// Получим объект IReference
  WorkerRef = References.ReferenceFactory('РАБ').GetComponent
  // Открыть набор данных справочника
  WorkerRef.Open()
  // Перейти к первой записи
  WorkerRef.First()
  // Выполнять, пока не конец справочника
  while not WorkerRef.EOF
    if WorkerRef.Requisites(“Дополнение”).Value == ‘Иванов Иван Иванович’
      // Открыть запись
      WorkerRef.OpenRecord()
      // Установить табельный номер
      WorkerRef.Requisites('Дополнение3').Value = "123"
      // Сохранить изменения
      WorkerRef.Save()
      // Закрыть запись
      WorkerRef.CloseRecord()
      // Если запись нашли, перейдем к последней записи
      // и выйдем из цикла
      WorkerRef.Last() 
   endif
   WorkerRef.next() 
  endwhile
  // Закрыть набор данных справочника
  WorkerRef.Close()

 

Авторизуйтесь, чтобы написать комментарий