首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >创建后如何更改DataModule的所有者?

创建后如何更改DataModule的所有者?
EN

Stack Overflow用户
提问于 2013-12-12 21:08:08
回答 4查看 2.4K关注 0票数 1

我正在尝试将一个DataModule传递给表单构造函数中的一个表单。我还希望表单成为DataModule的“所有者”,这样表单在关闭时就会销毁DataModule。这就产生了两个对象在其构造函数中相互需要的问题。

创建后,我尝试设置DataModule的所有者,但这是一个只读属性。

我的第二份表格如下:

代码语言:javascript
复制
type
  TSecondPopup = class(TForm)
  private
    FMyData: TMyData;
  public
    constructor Create(MyData: TMyData); reintroduce;
  end;

var
  SecondPopup: TSecondPopup;

implementation

{$R *.dfm}


constructor TSecondPopup.Create(MyData: TMyData);
begin
  FMyData := MyData;

  inherited Create(nil);
end;

我的数据模块中没有特殊的代码。

在我的主表单中,当显示第二种形式时,我想这样做:

代码语言:javascript
复制
procedure TMainApp.Button1Click(Sender: TObject);
var
  MyData: TMyData;
  SecondPopup: TSecondPopup;
begin
  MyData := TMyData.Create(nil);
  SecondPopup := TSecondPopup.Create(MyData);

  // Can't change owner now.  It is a read only property. 
  // MyData.Owner := SecondPopup;

  SecondPopup.Show;
end;

我知道我可以将DataModule更改为表单上的一个属性。然后我可以先创建表单,然后创建设置所有者的数据模块,最后在表单上设置属性。我试图在这个项目上使用构造函数依赖注入。当我有一个共享数据模块,主表单传递给多个表单时,它一直工作得很好。在这种情况下,主表单保持数据模块,直到它存在。在这种情况下,只有一个表单需要这个数据模块,所以我希望通过设置所有者来强制它管理数据模块的生命周期。

另一个选项是在关闭第二个表单时显式释放DataModule。但是,该表单无法知道调用方是否也将数据模传递给另一个表单。

是否有一种方法可以使用构造函数注入我的对象,但仍然获得用于管理生存期的表单?

目前使用德尔菲XE3。

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2013-12-12 23:24:46

使用NewOwner.InsertComponent(TheComponent)可以更改组件的所有权。而且,由于组件一次只能由一个组件拥有,RTL会自动从前一个所有者中删除所有权。

但是..。

另一个选项是在关闭第二个表单时显式释放DataModule。但是,该表单无法知道调用方是否也将数据模传递给另一个表单。

如果您想要将一个DataModule传递给多个表单,那么改变DataModule的所有权并不是解决方案:拥有DataModule的一个表单将无法影响它是否可以释放DataModule。因此得出的结论是,DataModule不能被任何形式所拥有,除非属于MainForm。(那么,我更愿意让Application拥有它,但这是一个品味问题。)

随后,您将需要在DataModule中为其附加的表单提供引用计数机制。

票数 4
EN

Stack Overflow用户

发布于 2013-12-12 22:38:27

您不必更改DataModule的Owner。您可以随时销毁DataModule,即使它指定了一个Owner。当DataModule被释放时,它将简单地从它的Owner中删除自己,这样就不会第二次释放它。如果采用这种方法,还应该添加对FreeNotification()的调用,以便在窗体仍在引用DataModule时,通知您是否释放了DataModule(由其Owner或其他任何人释放):

代码语言:javascript
复制
protected
  procedure Notification(AComponent: TComponent; Operation: TOperation); override;

代码语言:javascript
复制
constructor TSecondPopup.Create(MyData: TMyData);
begin
  inherited Create(nil);
  FMyData := MyData;
  if FMyData <> nil then
    FMyData.FreeNotification(Self);
end;

destructor TSecondPopup.Destroy;
begin
  if FMyData <> nil then
    FMyData.RemoveFreeNotification(Self);
  inherited Destroy;
end;

procedure TSecondPopup.Notification(AComponent: TComponent; Operation: TOperation);
begin
  inherited Notification(AComponent, Operation);
  if (Operation = opRemove) and (AComponent = FMyData) then
    FMyData := nil;
end;

如果您绝对希望通过TComponent.RemoveComponent()TComponent.InsertComponent()方法更改DataModule的TComponent.RemoveComponent()TComponent.InsertComponent(),这也是可行的:

代码语言:javascript
复制
constructor TSecondPopup.Create(MyData: TMyData);
begin
  inherited Create(nil);
  FMyData := MyData;
  if FMyData <> nil then
  begin
    // InsertComponent() will call RemoveComponent() internally for you...
    Self.InsertComponent(FMyData);
  end;
end;
票数 4
EN

Stack Overflow用户

发布于 2013-12-12 21:19:48

您希望让表单拥有数据模块。由于所有权是在施工时最自然地指定的,因此得出的结论是,应首先创建该表单。

因此,与其将数据模块传递给表单的构造函数,不如传递一些允许表单调用数据模块实例化的内容。例如,您可以将一个函数传递给表单的构造函数,该构造函数接受表单作为参数并返回新创建的数据模块。例如。

代码语言:javascript
复制
type
  TCreateDataModule = function(Owner: TMyForm): TMyDataModule of object;

您完全可以在表单之外创建数据模块,但没有所有者。将对象传递给窗体构造函数的。然后,表单可以销毁其析构函数中的数据模块。对我来说这是最干净的解决方案。我发现很难超越这一选择。

我认为你已经考虑过这个选择,但却以这样的理由拒绝了它:

但是,该表单无法知道调用方是否也将数据模块传递给另一个表单。

如果是这样,那就没有什么能救你了。除非两个对象使用引用计数或类似的方法,否则不能让两个对象同时负责整个生命周期。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/20554287

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档