Step 5 - Custom Properties (Object Pascal)
The component needs an additional property for the dialog's action verb, like "Save", to appear on the Do button. That verb is also combined with "Don't" on the Don't button. (More complex internationalization is beyond the scope of this topic.)
It would be simpler if you could rely on the presence of the button, and delegate to its Text to hold the verb. But the buttons are not there until the style is applied, and if the style is reapplied, the existing buttons are discarded. So the component needs to hold onto this string itself. Declare and implement a DoVerb property:
uses System.SysUtils, System.Classes, FMX.Types, FMX.Controls, System.UITypes; type TDialogButtonPanel = class(TPanel) private FDoVerb: string; function GetDoVerb: string; procedure SetDoVerb(AString: string); protected function GetStyleObject: TControl; override; procedure ApplyStyle; override; public constructor Create(AOwner: TComponent); override; published property DoVerb: string read GetDoVerb write SetDoVerb; property Align default TAlignLayout.Bottom; end; const DoButtonName = 'DoButton'; DontButtonName = 'DontButton'; CancelButtonName = 'CancelButton'; mrDont = -mrOK;
constructor TDialogButtonPanel.Create(AOwner: TComponent); begin inherited; Height := 46; Width := 300; Align := TAlignLayout.Bottom; DoVerb := 'Verb'; end; function TDialogButtonPanel.GetDoVerb: string; var Base: TFmxObject; begin Base := FindStyleResource(DoButtonName); if Base is TTextControl then FDoVerb := TTextControl(Base).Text; Result := FDoVerb; end; procedure TDialogButtonPanel.SetDoVerb(AString: string); var Base: TFmxObject; resourcestring Dont = 'Don'#39't %s'; begin FDoVerb := AString; Base := FindStyleResource(DoButtonName); if Base is TTextControl then TTextControl(Base).Text := AString; Base := FindStyleResource(DontButtonName); if Base is TTextControl then TTextControl(Base).Text := Format(Dont, [AString]); end; procedure TDialogButtonPanel.ApplyStyle; begin inherited; SetDoVerb(FDoVerb); end;
The StyleName for each of the three buttons is declared as a constant, along with the "negative OK" modal result code for the Don't button. The FDoVerb field is added to the object to contain the verb string.
At run time, the access sequence goes like this:
- When the application is executed, all its forms are created, including the dialog box form containing the button panel. The panel is instantiated by its
objectline when loading from the
.fmx. The constructor writes the default verb to the property, calling SetDoVerb. The field is set, and no buttons are found.
- Assigning the property values from the
.fmx, SetDoVerb is called again with the string saved by the designer (for example, "Save"), changing the field.
- When the dialog box is opened, it is painted, and one of the preliminary steps of painting a control is to apply its style if necessary, which includes the first time the control is painted. This ends up calling ApplyStyle, which is overridden here to reapply the verb string from the field. It redundantly reassigns the field, but now that the buttons are present, it also sets the verb in the Do button, and combines "Don't" and the verb in the Don't button.
- Rendering the buttons does not go through GetDoVerb, because the buttons that comprise the style are rendered directly, and they already have the appropriate text, assigned by the setter method. The getter method is used primarily by the Form Designer and any run-time code that gets the panel's properties. For completeness, the method will attempt to update the field from the Do button, if it exists; but unless the button is manipulated directly (bypassing encapsulation), its text and the field should already be synchronized.