質問

I have a Form which has data aware controls bound to datasets in a datamodule. I need to create additional instances of both the form and datamodule in the same application.

I deleted the global variable that was automatically created when the data module was first added to the project. To my delight, controls in the designer could still be bound to datasets in the data module without this global variable. I'm assuming the IDE is parsing the dfm of the datamodule so the designer can still "see" the datamodule. (without the data module loaded in the IDE the list of data sources is empty)

When I create two instances of the form and two instances of the datamodule at runtime both instances of the form appear to be bound to only the first data module that was created. Inspecting the second instance of the data module reveals that the Name property has a number suffix that wasn't there at design time.

The form depends on a lot of datasets in the data module. Is there an easier way to bind the second form instance to the second data module's datasets without resorting to hand coded SomeControl.DataSource := Module2.dsSomeData for every single control?

I'm open to alternative suggestions as well. One solution would be to move the datasets to the form itself. Still it seems a shame if design time data binding only works on singletons.

役に立ちましたか?

解決

Take a look at this question:
separate dataset instances using datamodules in delphi

Basically the answer is to create your DataModule, then your Form, then set the name of the created DataModule to an empty string. That will let the initial data binding happen but prevent other forms from seeing that Module.

In addition the next version that is created will still have the original name (no need for the numeric suffix).

他のヒント

I have a Form which has data aware controls bound to DataSets in a DataModule.

That is not possible. Indirectly, ok agreed, but there has to be a necessary DataSource in between. (From the rest of your question we have to distill the information that those DataSources are on the DataModule, but the question could certainly be more transparent about that.)

I deleted the global variable that was automatically created when the DataModule was first added to the project.

Good, stick to that custom!

To my delight, controls in the designer could still be bound to DataSets in the DataModule without this global variable. I'm assuming the IDE is parsing the dfm of the DataModule so the designer can still "see" the DataModule.

Same incorrectness/confusion between DataSource and DataSet, but you are partly right: for the IDE being able to find a DataModule, the following must be true:

  • The DataModule must be created/opened at least once during the session of the IDE (it may be closed afterwards during the session), see (*),
  • The unit of that DataModule must be present in the uses list of the Form unit.

When I create two instances of the Form and two instances of the DataModule at runtime, both instances of the Form appear to be bound to only the first DataModule that was created.

That is because you are depending on the automatic design time binding which does not work at runtime. That binding depends on the name of the DataModule. But this is not the only disadvantage of depending on design time binding, see (*).

Inspecting the second instance of the DataModule reveals that the Name property has a number suffix that wasn't there at design time.

Plus an underscore in front of that sequential number suffix. It seems to be by design. There cannot be multiple DataModules (nor Forms) with the same name, which is comparable with Components not capable of having the same name of that of a sibling or child Component. It is a little strange though, because when giving no Owner or even different Owners, the same rule still applies for DataModules and Forms, which is unlike default TComponent behaviour. I cannot find evidence nor an explanation in the RTL/VCL code. Maybe it has something to do with all DataModules and Forms being kept in the Screen variable. We just have to accept, but it is a no-problem.

The Form depends on a lot of DataSets in the DataModule. Is there an easier way to bind the second Form instance to the second DataModule's DataSets without resorting to hand coded SomeControl.DataSource := Module2.dsSomeData for every single control? ... One solution would be to move the DataSets to the Form itself.

Wherein dsSomedata being the DataSource!

Yes, there is an easier way. Instead of placing the DataSets on the Form, place the DataSources on the Form. Typically, a Form often has only a single or few DataSources compared to the number of data controls. That way the data control - DataSource binding remains intact (because both are read from the same DFM), and only the DataSet settings of the DataSources remain to be set manually:

  TCustomerForm = class(TForm)
    DataSource: TDataSource;
    procedure FormCreate(Sender: TObject);
  private
    FData: TCustomerDataModule;
  end;

procedure TCustomerForm.FormCreate(Sender: TObject);
begin
  FData := TCustomerDataModule.Create(Self);
  DataSource.DataSet := FData.Query;
end;

Or, when you want to create the Form from the DataModule:

  TCustomerForm = class(TForm)
    DataSource: TDataSource;
  private
    FData: TCustomerDataModule;
    procedure SetData(Value: TCustomerDataModule);
  public
    property Data: TCustomerDataModule read FData write SetData;
  end;

procedure TCustomerForm.SetData(Value: TCustomerDataModule);
begin
  if FData <> Value then
  begin
    FData := Value;
    DataSource.DataSet := FData.Query;
  end;
end;

(*) In large projects with many Forms and DataModules, it is very common to not open every DataModule in the IDE, and (DataSource.)DataSet settings easily can get lost. Being dependent on the designtime binding by DataModule name then may result in your Forms never showing any data. This is a bug which is hard to foresee whithout checking every Form's (DataSource.)DataSet settings.

Doing it all in the above outlined manner ensures correct DataModule creation at runtime, and ensures all designtime capabilities and cleverness of the IDE providing DataSets, Fields, etc...

I have the same issue. I used the following solution.

My 2 instances of the form share the same DataModule instance. The 2 forms don't show up at the same time. I have the advantage, that the 2 forms show always the same data, since my data is in memory cached, with the TCLientDataSet.

e.g.

_dmSachkonto := TCachedDataModules.Instance.Add(TdmSachkonto) as TdmSachkonto;

TdmSachkonto is my DataModule.

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top