We can also take the Limited property to the next level by firing an event each time the value of the property is read. The simplest event type that we can create is a notification, using the TNotifyEvent type:
type TNotifyEvent = procedure (Sender: TObject) of object;
To create the OnAccess event, you have to add a TNotifyEvent field to the private section and the event's declaration in the published section (see Figure 24-17). Although you can name your events anything you like, event names usually begin with "On":
Figure 24-17: The new OnAccess event
private FOnAccess: TNotifyEvent; published property OnAccess: TNotifyEvent read FOnAccess write FOnAccess;
Now that the interface part of the event is done, you have to write the event's implementation. The implementation of events is actually quite simple. Since the TNotifyEvent type (like all other procedures of object) is a method pointer, you only have to check whether the method pointer points to a valid memory location and call it:
if Assigned(FOnAccess) then FOnAccess(Self); { pass Self as the Sender parameter }
The best way to implement an event is to create a protected virtual method. By creating a method to fire the event, you'll have less typing to do if you decide later on that you want to fire the event somewhere else:
procedure DoAccess; virtual; ... procedure TSimple.DoAccess; begin if Assigned(FOnAccess) then FOnAccess(Self); { pass Self as the Sender parameter } end;
The following listing shows the entire TSimple component. The OnAccess event is fired by calling the DoAccess method in the read method of the Limited property.
Listing 24-12: The TSimple component with the OnAccess event
unit Simple; interface uses SysUtils, Classes, Dialogs; type TSimple = class(TComponent) private { Private declarations } FLimited: Integer; FAccessCount: Integer; FOnAccess: TNotifyEvent; protected { Protected declarations } function GetLimited: Integer; virtual; procedure SetLimited(Value: Integer); virtual; procedure DoAccess; virtual; public property AccessCount: Integer read FAccessCount; { read-only } published { Published declarations } property Limited: Integer read GetLimited write SetLimited; property OnAccess: TNotifyEvent read FOnAccess write FOnAccess; end; procedure Register; implementation procedure Register; begin RegisterComponents('My Components', [TSimple]); end; procedure TSimple.SetLimited(Value: Integer); begin if (Value >= 0) and (Value <= 100) then FLimited := Value else raise ERangeError.Create('Give me a number from 0 to 100!'); end; function TSimple.GetLimited: Integer; begin Inc(FAccessCount); Result := FLimited; { fire the OnAccess event } DoAccess; end; procedure TSimple.DoAccess; begin if Assigned(FOnAccess) then FOnAccess(Self); { pass Self as the Sender parameter } end; end.
The following event handler shows that the OnAccess event indeed works (see Figure 24-18):
Figure 24-18: Using the OnAccess event
procedure TForm1.Simple1Access(Sender: TObject); begin ListBox1.Items.Add('The Limited property was last accessed on: ' + DateTimeToStr(Now)); end;