"Object Aware" Элементы управления GUI - PullRequest
8 голосов
/ 01 марта 2011

У меня есть несколько бизнес-объектов, написанных на Delphi с настраиваемой схемой сохранения базы данных, которая наконец работает для моих нужд. Ок, отлично. Теперь пришло время для реализации GUI. И тут начинаются проблемы.

Как правильно привязать мой объект к графическому интерфейсу?

Я не могу использовать элементы управления Data Aware, так как я изолировал все компоненты доступа к данным на уровне ORM, поэтому я начинаю писать некоторые элементы управления Object Aware с помощью модуля RTTI (я работаю с Delphi 2010), но у меня есть ощущение, что я иду не в ту сторону ...

Некоторые идеи о том, как решить эту проблему, используя только элементы управления VCL?

Ответы [ 5 ]

6 голосов
/ 01 марта 2011

У вас есть несколько шаблонов для соединения ORM с пользовательским интерфейсом.

См., Например, шаблон Модель GUI Mediator .Короче говоря, вы пишете наблюдателя, который будет отражать содержимое ORM в компонентах пользовательского интерфейса, и наоборот.Это было реализовано, например, в платформе tiOpf для Delphi (по этой ссылке есть видео).

Другой подход - отобразить ваши данные во время выполнения: вы создаете форму, как обычно, затемВы заполняете содержимое в событии OnShow, затем кнопка « Сохранить » или « OK » подтвердит правильность, а затем сохранит содержимое в записи ORM.Это то, что делается в основном примере приложения нашей платформы .Легко кодировать в этом простом примере, но может привести к спагетти-коду, если у вас много полей и проверок для работы.

Последний подход - позволить вашему ORM создать форму.

В нашей структуре вы можете определить некоторые свойства пользовательского интерфейса для каждой таблицы в отдельной структуре.Затем единица создаст форму со всеми редактируемыми полями вашего объекта ORM.Ссылки на другие записи будут отображаться в виде поля со списком, логические значения в виде флажков, в качестве радиобоксов и т. Д.Затем фильтрация (например, обрезка текстового поля из пробелов слева или справа) и проверка (например, убедитесь, что значение поля уникально или действительный IP-адрес) обрабатывается не в части пользовательского интерфейса, а в бизнесе.Сама логика, т. е. ORM .

ИМХО, обязательно сохранять истинную многоуровневую архитектуру.То есть пользовательский интерфейс должен полагаться в основном на бизнес-логику.Например, проверка данных должна быть частью ORM, а не UI.Например, если вы решите добавить веб-клиент в клиентское приложение Delphi, вам не придется кодировать проверку в другой раз: она будет общей для обоих клиентов, отдельно от деталей реализации пользовательского интерфейса.

2 голосов
/ 01 марта 2011

Что вы могли бы сделать (хотя у меня нет примеров кода), это использовать комбинацию

  • класс помощников или классов-перехватчиков
  • интерфейсы привязки для отдельных объектов домена и / или списков объектов домена

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

Классы-перехватчики - это просто классы-потомки с тем же именем, что и их предок:

uses
  stdctrls;

type
  TButton = class(stdctrls.TButton)
  end;

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

Преимущество классов перехватчиков:

  • Вы можете продолжить разработку пользовательского интерфейса, используя стандартный VCL или сторонние элементы управления.
  • Вы получаете все преимущества потомков.
  • Вам не нужно создавать или устанавливать свои собственные элементы управления.
  • Нет необходимости в специальных классах картографирования или использовании RTTI.
  • Легко (ну, относительно легко) интегрируется в тестируемый пользовательский интерфейс (DUnit-) в соответствии со статьей Джулиана Бакналла об этом в (отдельном) журнале Delphi, как указано в этом вопросе / ответе: Unit- тестирование обработчиков событий мыши

Псевдосэмпл управления перехватчиком с интерфейсом привязки / интерфейсом команды:

uses
  stdctrls;

type
  ICommandAction = interface(IInterface)
    function IsEnabled: Boolean;
    procedure Execute;
    procedure Update;
  end;

  IBindSingle = interface(IInterface)
    function GetValueFromControl: string;
    procedure LoadValueIntoControl(const aValue: string);
  end;

  TButton = class(stdctrls.TButton, ICommandAction)
  protected
    function IsEnabled: Boolean;
    procedure Execute;
    procedure Update;
  end;

  TEdit = class(stdctrls.TEdit, IBindSingle)
    function GetValueFromControl: string;
    procedure LoadValueIntoControl(const aValue: string);
  end;
Реализация

может быть такой:

  function TButton.IsEnabled: Boolean;
  begin
    Result := Self.Enabled;
  end;

  procedure TButton.Execute;
  begin
    Self.Action.Execute;
  end;

  procedure TButton.Update;
  begin
    Self.Action.Update;
  end;

  function TEdit.GetValueFromControl: string;
  begin
    Result := Self.Text;
  end;

  procedure LoadValueIntoControl(const aValue: string);
  begin
    Self.Text := aValue;
  end;
1 голос
/ 01 марта 2011

Мой нынешний клиент делал свои собственные классы "картографа" в прошлом (до того, как я пришел).Их объекты данных имеют поля (которые являются объектами), и вы можете сопоставить эти поля с элементом управления.Я расширил фреймворк, используя MVC-подобный подход:

edtTarraCode: TAdvEdit;

procedure TframTarraTab.InitMapping;
begin
  ...
  Mapper.AddMapping(edtTarraCode, Controller.DataModel.tarID);
  ...
end;

В расчете на элемент управления создается простой класс "отображения":

TMappingAdvEdit = class(TBaseEditMapping)
protected
  procedure InitControl; override;

  procedure AppData2Control; override;
  procedure Control2AppData; override;
end;

Нет ракетостроения, и, возможно, найдутся лучшие решениядоступно в настоящее время (это работало в D6 и ниже :-)), но это работает достаточно хорошо для клиента.

Кстати: также используется генератор объектов данных.Таким образом, если поле изменяется в базе данных (например, tarra.tarid изменяется на tareID), мы получаем ошибку компилятора, потому что «tarid» больше не существует.Это работает намного лучше, чем отображение «фиксированной строки» (ошибки времени выполнения).

0 голосов
/ 17 июня 2013

Взгляните на набор данных EverClassy по адресу http://www.inovativa.com.br. Он может удовлетворить ваши потребности.EverClassy Dataset - это набор данных Delphi, предназначенный для заполнения объектами, а не записями из системы баз данных.

С этим компонентом у вас будет возможность взаимодействовать с вашими объектами домена с компонентами информационного обеспечения, что даст вам большие возможности для созданияваш графический интерфейс.

0 голосов
/ 01 марта 2011

В настоящее время нет способа сделать это, используя только элементы управления VCL.Я знаю, что Lazarus имеет набор основанных на RTTI элементов управления данными;Вы можете посмотреть на них для некоторых основных идей.Но это сложнее, чем вы думаете на первый взгляд.Например, в отличие от набора данных, объект не имеет встроенного механизма сигнализации при изменении значений его членов.Это означает, что, если ваши элементы управления привязкой данных не владеют объектом полностью, и ничто другое не имеет к нему доступа, некоторый другой код может изменить какое-то значение, и тогда это изменение не будет отражено в интерфейсе пользователя.В последние несколько лет от команды Delphi я слышал о том, как расширить объектную модель или модель RTTI, чтобы обеспечить лучшее связывание данных, но до сих пор осталось несколько лет.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...