【问题标题】:Responding to linked Delphi Component Events响应链接的 Delphi 组件事件
【发布时间】:2011-01-04 11:32:42
【问题描述】:

我有一个自定义组件(删减)

 TMyComponent = class(TComponent)
 public
    procedure ClientConnected;
 published 
    property ClientSocket: TClientSocket Read ...etc

现在我在 ClientSocket 调用 ClientConnected 的 OnConnect 事件中,例如

 procedure TForm1.ElvinClient1Connect(Sender: TObject; Socket: TCustomWinSocket);
 begin
   MyComponent1.ClientConnected;
 end;

有没有办法在 TMyComponent 类中做到这一点而不需要外部事件?

编辑:
忘了说ClientSocket不是由组件创建的,它是在运行时分配的。

我也尝试过使用私有 Proc

 procedure TMyComponent.OnClientConnected(sender: TObject);
 begin
  ClientConnected;
  if Assigned(oldOnClientConnected) then
   oldOnClientConnected(sender);
 end;

以及 ClientSocket 的设置器

 procedure TMyComponent.SetClientSocket(const Value: TClientSocket);
 begin
   fClientSocket := Value;
   oldOnClientConnected:= fClientSocket.OnElvinConnected;
   fClientSocket.oldOnClientConnected:= OnClientConnected;
 end;

但我感觉它会回来困扰我......

【问题讨论】:

    标签: delphi events components delphi-7


    【解决方案1】:

    您需要成功挂钩分配的 ClientSocket(我们称之为子组件)的事件是:

    • 不“干扰”正常的设计时行为:仅在运行时分配您自己的事件处理程序
    • 保存用户(开发者)分配的子组件事件处理程序
    • 确保安全地调用保存的方法。
    • 允许运行时重新分配子组件。
    • 记录您在幕后所做的事情,因为开发人员的无知可能会搞砸所有事情

    例如:

    TMyComponent = class(TComponent)
    private
      FClientSocket: TClientSocket;
      FSavedClientConnected: TClientConnectedEvent;  //Look for the Event type you want to save
      procedure ClientConnected(AValidFirm: TFirm);  //This method shall have a valid TClientConnectedEvent firm
      procedure Hook;                                //Set my own event handlers to the child component
      procedure UnHook;                              //Free the child component of my own event handlers ant let it as it was before
    protected
      procedure Loaded; override;                    //Touch the child component after the container streaming load is finished
      procedure Notification(AComponent: TComponent; Operation: TOperation); override;
                                                     //Stay safe if the child component goes away
    public
      destructor Destroy; override;                  //Cleanup the child component if I'm going away
    published
      property ClientSocket: TClientSocket read FClientSocket write SetClientSocket;  
                                                     //let's play
    end;
    
    procedure TMyComponent.SetClientSocket(Value: TClientSocket);
    begin
      if FClientSocket <> Value then
      begin
        UnHook;
        FClientSocket := Value;
        Hook;
      end;
    end;
    
    procedure TMyComponent.Hook;
    begin
      if (csDesigning in ComponentState) or (csLoading in ComponentState) then Exit;
      if Assigned(FClientSocket) then
      begin
        FSavedClientConnected := FClientSocket.SavedClientConnected;
        FClientSocket.ClientConnected := ClientConnected;
      end;
    end;
    
    procedure TMyComponent.UnHook;
    begin
      if Assigned(FClientSocket) then
      begin
        FClientSocket.ClientConnected := FSavedClientConnected;
        FSavedClientConnected := nil;
      end;
    end;
    
    procedure TMyComponent.Loaded;
    begin
      Hook;
    end;
    
    destructor TMyComponent.Destroy;
    begin
      UnHook;
    end;
    
    procedure TMyComponent.Notification(AComponent: TComponent; Operation: TOperation);
    begin
      if (AComponent = FClientSocket) and (Operation = opRemove) then
        UnHook;
      FClientSocket := nil;
    end;
    
    //the important part!
    procedure TMyComponent.ClientConnected(AValidFirm: TFirm);
    begin
      DoMyOwnStuffWith(FClientSocket);
      if Assigned(FSavedClientConnected) then
        FSavedClientConnected(AValidFirm);
      //as you see, you can call the saved event before, after or in the mid of your own stuff.
    end;
    

    当然,它不会编译(我敢肯定,从未尝试过),但这只是一个简短的想法。也许我错过了一些东西,如果您遇到错误,请告诉我进行评论。

    【讨论】:

    • 谢谢你,看起来基本上是我开始做的,但有更多的想法:)
    【解决方案2】:

    是的,您可以在您的组件中实现一个带有该签名的过程,并在您构造 TClientSocket 时将其分配给事件。

    但是...由于您公开了 ClientSocket,这意味着可以使用您的组件从代码中覆盖该事件分配。根据事情发生的顺序以及谁将使用您的组件,这对您来说可能不是问题 - 但您可能需要考虑将 ClientSocket 设为私有或受保护,或者可能编写一个简单的代理,然后使用确保在用户的事件处理程序之前调用您的 ClientConnected。

    【讨论】:

    • 忘了说这个,但是ClientSocket不是由组件创建的,它是在设计时分配的。我认为不管我怎么做,这可能会很乱。
    • 分配或创建它并不重要,只要您“及时”分配事件......但不,它不太可能是漂亮的。就个人而言,我会说编写代理是您最好的选择,但这只是基于对 TClientSocket 的快速了解,这实际上取决于您的确切需求。当然,如果它绝对必须是从您的组件外部提供的普通 TClientSocket,那么除了您当前的解决方案之外,我真的看不出您能做什么。
    【解决方案3】:

    也许您可以覆盖 TClientSocket 类,并在调用事件的地方也调用您自己的例程。唯一的障碍是您需要一个标记为虚拟或动态的例程来执行此覆盖,我还没有检查 TClientSocket 是否这样做。

    在这种情况下,您仍然可以根据需要将客户端套接字公开为 TClientsocket。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-05-15
      • 2015-08-31
      • 1970-01-01
      • 2017-08-05
      • 2010-10-31
      • 2011-12-28
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多