Terry Thompson
Terry Thompson

Reputation: 533

Can't set Fire Monkey Form property

I am trying to initialize form properties in the program source file in a Fire Monkey application and it throws an exception. Here is the code:

uses
    System.StartUpCopy,
    FMX.Forms,
    uMainForm in 'Units\uMainForm.pas' {MainForm},
    UDataModule in 'Units\UDataModule.pas' {DataMod: TDataModule},
    DataHelperClasses in 'Units\DataHelperClasses.pas',
    EXDIntf in 'Units\EXDIntf.pas',
    Exd in 'Units\Exd.pas';

    {$R *.res}
    var
      ViewModel: TEXDViewModel;
    begin
      Application.Initialize;
      Application.CreateForm(TDataMod, DataMod);
      Application.CreateForm(TMainForm, MainForm);
      ViewModel := TEXDViewModel.Create;
      MainForm.Data := DataMod;
      MainForm.ViewModel := ViewModel;  //This throws an access violation exception
      ViewModel.Data := DataMod;
     Application.Run;
end.

I have no problem doing this in a VCL app. How do I fix it?

Upvotes: 3

Views: 511

Answers (1)

Dalija Prasnikar
Dalija Prasnikar

Reputation: 28512

There is difference in behavior between VCL and FMX - FireMonkey Application.CreateForm method. While in VCL CreateForm actually creates form and after that call form variable is fully initialized and ready to be used, in FMX CreateForm does not create form and form variable would still be uninitialized - nil - after that call. Because of that using form variable throws AV.

FMX.TApplication.CreateForm

CreateForm does not create the given form immediately. It just adds a request to the pending list. RealCreateForms creates the real forms.

FMX has Application.RealCreateForms method that is automatically called in Application.Run. If you need to use form variables before that, you can call Application.RealCreateForms yourself. After that call you can safely use form variables you added to the list with Application.CreateForm

Keep in mind that Application.RealCreateForms will go through form creation process only once, so you have to call it after you made all calls to Application.CreateForm or you will end up with some unitialized forms.

begin
  Application.Initialize;
  Application.CreateForm(TDataMod, DataMod);
  Application.CreateForm(TMainForm, MainForm);

  // this forces creation of FireMonkey forms
  Application.RealCreateForms;
  ....

Note: On Windows and OSX platforms RealCreateForms is first thing that is called in Application.Run, so it does not matter whether it is called by you or automatically. However, on Android and iOS platforms additional (initialization) logic happens before RealCreateForms is called in Application.Run, if you develop for those platforms, you should proceed with caution when using RealCreateForms and watch for potential side-effects. Probably the best option for mobile platforms would be to move your custom initialization into Form OnCreate event.

Upvotes: 8

Related Questions