Разработка кроссплатформенных мобильных приложений в DelphiЧасть #1
Часть #2
Часть #3

В четвертой части настоящего цикла мы вновь возвратимся к разработке «настольного» приложения и попытаемся более подробно разобраться с технологией связывания объектов LiveBinding. Данный механизм универсален и подходит как для мобильных, так и настольных приложений. Более того, этот механизм работает и в VCL. Знакомство же с LiveBinding лучше начать именно в классическом проекте.

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

Итак, в модуле данных поместим два компонента TFDTable и настроим их на работу с таблицами tblUnit и tblFoodstuff (по аналогии с набором данных для работы с таблицей tblRecipe). Двойным щелчком на компоненте откроем редактор полей, добавим все поля (пункт контекстного меню Add all fields).

Важно понимать, что практически во всех ре��лизациях компоненты наборов данных наследуются от класса TDataSet и работают с некоторым набором полей. Здесь имеются в виду экземпляры классов, наследников TField (TIntegerField, TStringField и т.д.). Набор полей можно создать в режиме проектирования (design-time) и настроить свойства полей с помощью «инспектора объектов». Если рассматривать TFDTable, то помимо полей, соответствующих физическим полям таблицы, можно создать и другие типы полей, например, вычисляемое (Caclulated) или подставляемое (LookUp) поле. Значения этих полей будут вычисляться динамически в ходе работы программы, а не браться из источника данных. Чуть ниже мы рассмотрим пример создания таких полей.

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

Ниже приведен фрагмент файла формы модуля данных uDM.dfm, содержащий описание одного из наборов данных и связанных с ними полей. Текстовое представление формы можно получить, если в контекстном меню формы выбрать пункт «View as Text». Для того, что бы вернуться в обычный режим представления формы, следует нажать «View as Form».

  object FDTUnits: TFDTable
    IndexFieldNames = 'Id'
    Connection = FDConnection1
    UpdateOptions.UpdateTableName = 'tblUnit'
    TableName = 'tblUnit'
    Left = 112
    Top = 208
    object FDTUnitsId: TFDAutoIncField
      FieldName = 'Id'
      Origin = 'Id'
      ProviderFlags = [pfInWhere, pfInKey]
      ReadOnly = True
    end
    object FDTUnitsUnitName: TStringField
      FieldName = 'UnitName'
      Origin = 'UnitName'
      Required = True
      Size = 25
    end
    object FDTUnitsAbbr: TStringField
      FieldName = 'Abbr'
      Origin = 'Abbr'
      Required = True
      Size = 7
    end
  end



Созданные наборы данных, необходимо открыть при запуске программы. Модифицируем процедуру ConnectToDB следующим образом:

function TDM.ConnectToDB: Boolean;
begin
  try
    FDConnection1.Connected := True;
    FDTRecipe.Open;
    FDTUnits.Open;
    FDTFoodstuff.Open;

  except

  end;
  Result := FDConnection1.Connected;
end;


Следующим шагом разработки приложения станет создание новой формы для отображения и редактирования таблицы (списка) единиц измерения. Естественно, это будет FM HD форма. Значение свойства Position установим как poMainFormCenter, для того, что бы данная форма отображалась посредине главной формы.

В список используемых модулей секции implementation добавим модуль данных:

implementation

{$R *.fmx}

uses uDM;


Поместим на форме компоненты TGrid, TPanel. На панели поместим кнопку, поле ввода и метку TLabel, как это показано на рисунке. Единственное назначение кнопки – закрыть форму. Свойству ModalResult определим значение mrOk.

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

FireMonkey форма

С помощью редактора LiveBinding свяжем визуальные компоненты с источниками данных. В самых общих чертах, LiveBinding это механизм, позволяющий связывать свойства различных объектов, но не при помощи жёсткой ссылочной компилированной связи, а на основе гибких выражений (expressions). Механизм LiveBindings базируется на шаблоне «наблюдатель» (observer). Так, изменение некоторого свойства объекта А, с помощью LiveBinding может повлечь за собой изменение свойства объекта Б. Связи между объектами могут быть однонаправленными и двунаправленными. Такой подход очень удобно использовать для отображения данных из наборов данных. Фактически, если в стандартном подходе VCL для отображения данных из таблиц требовались специальные DB-ориентированные (DB-Aware) визуальные компоненты, то LiveBindings позволяет использовать для этой цели самые обычные элементы управления («контролы). Более того, визуальные компоненты не требуют специальной подготовки, для работы с LiveBindings. Преимущество такого подхода очевидно. Давайте рассмотрим данный процесс чуть внимательнееболее подробно.

Итак, откроем LiveBinding Designer и найдем элемент, соответствующий набору данных, FDTUnits. Если элементы из модуля данных не отображаются в LiveBinding дизайнере, то следует сделать обновление (в контекстном меню выбрать пункт Refresh Designer). Попытаемся связать значение свойства Text поля ввода Edit1 со значением поля UnitName в наборе данных. Используем обычное перетаскивание (drag-n-drop).

LiveBinding Designer

Что же произошло на самом деле?

Помимо того, что в дизайнере визуально отобразилась связь, на форме появилось два новых не визуальных компонента. Компонент TBindSourceDB с помощью свойства DataSet осуществляет связь с исходным набором данных (в нашем случае DM.FDTUnits). Обратите внимание на то, что как только была установлена связь между свойством визуального компонента и полем, в LiveBinding дизайнере объект DM.FDTUnits оказался вложенным в новый объект BindSourceDB1, и этот объект появился на форме.

LiveBinding

Нетрудно догадаться, какое значение свойства DataSet будет у данного объекта. Для тех, кто мыслит в терминах «классической VCL разработки», проще всего воспринимать TBindSourceDB как некий аналог TDataSource. Вы можете точно также «бросить» этот компонент на форму и указать значение свойства DataSet. А затем «привязать» к нему контрол. Только теперь это будет не специальный DB-контрол, а любой визуальный компонент. А, следовательно, вы должны указать, какое именно свойство компонента и каким образом должно отображать (и, возможно, изменять) данные из набора данных. Давайте посмотрим, как это сделать.

Кроме BindSourceDB1 на форме появился и еще один объект — BindingsList1. Он является хранилищем для всех связей между объектами. Связи эти могут быть разных типов. Как видно из рисунка, в нашем случае в BindingsList была добавлена связь типа TLinkControlToField.

FireMonkey LiveBinding. Редактор связей

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

Oblect inspector

Если вы попробуете добавить новую связь, то увидите, что существует довольно много различных типов связей, практически позволяющих связать «всё со всем».

Дерево объектов. BindingsList

Теперь свяжем Grid и BindNavigator с набором данных. Для компонента BindNavigator достаточно задать свойство DataSource. При этом в списке связей BindingsList1 новая связь не создается. А вот при связывании Grid’а, напротив, создается объект типа TLinkGridToDataSourceBindSourceDB.

image

В инспекторе объектов мы можем отредактировать список полей. Для этого вызовем свойство Columns и в редакторе полей нажмем кнопку Add All Fields. К слову, этот редактор очень напоминает редактор полей в TDBGrid. Для каждого из полей можно отредактировать свойства, в частности ширину поля и текст заголовка. Кроме этого, можно создать новое поле, и задать выражение (свойство CustomFormat) для отображения в столбце таблицы. Так для того, что бы отобразить комбинацию Id и аббревиатуры, мы можем задать такое выражение:

DataSet.FieldByName('Id').AsString +" - "+DataSet.FieldByName('Abbr').AsString


Как следует из вышесказанного, механизм LiveBinding предоставляет достаточно широкие возможности для отображения данных. LiveBinding дизайнер, в свою очередь, позволяет визуализировать и упростить процесс связывания визуальных компонентов с источником данных.
В заключение рассмотрим еще один прием работы с LiveBinding. В дизайнере сделайте активным поле Abbr элемента DM. FDTUnits и в контекстном меню выберите пункт Link to new control… (Связать с новым элементом управления…). В появившемся списке выберите значение TEdit.



Нажмите кнопку «Ок» и на форме будет размещен новый элемент управления TEdit и «приклеенная» к нему метка TLabel. Вам останется только поместить данный объект в нужную позицию и задать нужное значение свойства Text метки.



Вызов форм редактирования списков из главной формы организуем с помощью меню. На главной форме поместим компонент TMainMenu. Двойным щелчком вызовем редактор меню. И создадим несколько пунктов, так как это показано на рисунке.



Для пункта меню “Единицы измерения” зададим следующий обработчик события OnClick:

procedure TfMain.aSprUnitExecute(Sender: TObject);
begin
fSprUnits.ShowModal;
end;


Естественно, модуль с формой-списком необходимо подключить к главной форме.

implementation

{$R *.fmx}

uses uAddRecipe, uSprUnit;


Форму-список продуктов вы можете сделать по аналогии.

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

До следующей пятницы!