|
Software Development Kit to the Delphi-Win32 and Free Pascal compilers |
| Home > Wiki > Creating attributes |
Creating attributesenglish (en) | português (br) User created attributes are created when there is a need to distribute the same functionality to different classes, or when there is need for a customization not provided by PressObjects' Data Type framework. Examples: It's possible to have a TTelephone attribute that formats a number with parentheses, space and dash; or TCPF that validates the input for correct digits and formats the output; or for container attributes (Master-Details), such that the methods point to the correct class and takes advantage of the strong typing of Object Pascal.
[edit] Creating an attributesDefinition of an attributes is done in three simple steps:
[edit] Simple attributesThese are all the attributes that do not descent from TPressStructure, in other words, it should not be neither aggregates or compositions (foreign keys or master-detail) [edit] Verifing user inputThe following example creates an attribute that verifies the user input:
TCPF = class(TPressString)
protected
procedure SetValue(const AValue: string); override;
end;
...
procedure TCPF.SetValue(const AValue: string);
begin
if not IsValidCPF(AValue) then
// erro
inherited;
end;
...
initialization
TCPF.RegisterAttribute;
finalization
TCPF.UnregisterAttribute;
To use the new attribute in a business class:
TClient = class(TPressObject)
_CPF: TCPF;
protected
class function InternalMetadataStr: string; override;
end;
...
class function InternalMetadataStr: string;
begin
Result := 'TClient IsPersistent (' +
'CPF: TCPF;' +
')';
end;
From now on, whenever CPF is changed (by the MVP or by assigning a new value directly to the object), the routine will be called to valid the input. [edit] Formatting data for displayTo format for display, follow the steps in the previous section and overload the GetDisplayText method, like in the following example: TTelefone = class(TPressString) protected function GetDisplayText: string; override; end; ... function TTelefone.GetDisplayText: string; begin Result := FormatPhone(Value); end; Beyond registering the component and using the business object properly. Whenever the component has focus the formatted content will be used instead of the native content. [edit] Container attributesOne of the great benefits of registering a container attribute is the ability to use the compiler's strong type to validate the use of the methods to maintain the container. For example: var VItem: TOrderItem; begin VItem := AnOrder.Items.Add; The compiler will complain because the method Add returns a TPressObject, which is the base class for all the business objects. Since we are manipulating an Order Item, we know about it, we need to cast it so that the compiler validates the line. Or instead of this, it's possible to create a new class that understands our container: TOrderItemParts = class(TPressParts) public function Add: TOrderItem; class function ValidObjectClass: TPressObjectClass; override; end; ... function TOrderItemParts.Add: TOrderItem; begin Result := inherited Add as TOrderItem; end; class function TOrderItemParts.ValidObjectClass: TPressObjectClass; begin Result := TOrderItem; end; ... initialization TOrderItemParts.RegisterAttribute; finalization TOrderItemParts.UnregisterAttribute; end; Note: the method ValidObjectClass has to be overriden to return the correct target class. Just use the attribute in the business class. Note that the declaration in the metadata and the attribute accessor in its own class:
TOrder = class(TPressObject)
_Items: TOrderItemParts;
protected
class function InternalMetadataStr: string;
public
property Items: TOrderItemParts read _Items;
end;
...
class function TOrder.InternalMetadataStr: string;
begin
Result := 'TOrder IsPersistent (' +
'Items: TOrderItemParts;' +
')';
end;
|
Personal tools |