我有一些用Delphi编写的业务对象,它有一个自定义的数据库持久性方案,最终可以满足我的需求。太好了。现在是GUI实现的时候了。这里开始出现问题。
如何正确地将我的对象绑定到GUI?
我无法使用Data Aware控件,因为我将所有数据访问组件隔离到ORM层,因此我开始使用RTTI单元编写一些“Object Aware”控件(我正在使用Delphi 2010),但我有感觉我走错路了......
有关如何仅使用VCL控件解决此问题的一些想法?
答案 0 :(得分:6)
您有几种将ORM与用户界面链接的模式。
例如,参见Model GUI Mediator模式。简而言之,您编写了一个观察者,它将ORM内容反映到UI组件中,反之亦然。这已在tiOpf framework for Delphi中实现(此链接包含视频)。
另一种方法是在运行时映射数据:您像平常一样设计表单,然后填写OnShow
事件中的内容,然后填写“保存”或“< em> OK “按钮将验证然后将内容保存到ORM记录中。这是在main Sample application of our framework中完成的。在这个简单的示例中很容易编码,但如果您有很多字段和验证可以操作,可能会导致意大利面条代码。
最后一种方法是让你的ORM创建表单。
在我们的框架中,您可以在专用结构中定义有关每个表的一些UI属性。然后是你的ORM对象的a single unit will create a form with all editable fields。其他记录的链接将显示为组合框,布尔值显示为复选框,设置为radioboxes等。然后处理过滤(例如从左侧或右侧的空格修剪文本字段)和验证(例如确保字段值是唯一的或有效的IP地址)not in the UI part, but in the business logic itself, i.e. the ORM。
恕我直言,必须保持真正的多层架构。也就是说,UI必须主要依赖于业务逻辑。例如,数据验证必须是ORM的一部分,而不是UI的一部分。例如,如果您决定将Web客户端添加到Delphi客户端应用程序中,则无需再次对验证进行编码:对于两个客户端而言,它们将与UI实现细节分开。
答案 1 :(得分:2)
你能做什么(虽然我没有代码样本)是使用
的组合班级帮助者的缺点是他们没有得到官方支持,你不能在你正在帮助的班级中添加任何字段。
拦截器类只是与其祖先同名的后代类:
uses
stdctrls;
type
TButton = class(stdctrls.TButton)
end;
您可以将拦截器类放在他们自己的单元中,并根据需要使用它。只需确保这些单位包含在标准单位之后,因此您的后代在运行时使用。
拦截器类的好处:
带有绑定接口/命令接口的拦截器控制的伪示例:
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;
答案 2 :(得分:1)
我现在的客户过去曾经做过自己的“映射器”课程(在我来之前)。 它们的数据对象具有字段(对象),您可以将这些字段映射到控件。我通过使用类似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”不再存在。这比“固定字符串”映射(运行时错误)要好得多。
答案 3 :(得分:0)
目前无法仅使用VCL控件执行此操作。我知道Lazarus有一套基于RTTI的数据感知控件;你可能想看看他们的一些基本想法。但它比你最初想象的要困难得多。例如,与数据集不同,对象在其成员的值发生变化时没有内置的信号机制。这意味着除非您的数据绑定控件完全拥有该对象而其他任何东西都无法访问它,否则其他一些代码可能会更改某些值,然后该更改不会反映在UI中。
在过去的几年里,我听说过Delphi团队关于扩展对象模型或RTTI模型以实现更好的数据绑定的各种事情,但无论如何还是几年之后。
答案 4 :(得分:0)
在http://www.inovativa.com.br查看EverClassy Dataset。它可能满足您的需求。 EverClassy Dataset是一个Delphi数据集,设计用于填充对象而不是数据库系统中的记录。
使用此组件,您将有机会将您的域对象与数据软件组件进行互操作,这将为您提供构建GUI的强大功能。