响应链接的Delphi组件事件

时间:2010-01-13 03:29:56

标签: delphi events components delphi-7

我有自定义组件(缩减)

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

现在我已进入ClientSocket Call ClientConnected的OnConnect事件,例如

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

有没有办法在TMyComponent类中执行此操作而不需要外部事件?

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

我也尝试过私人过程

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

和ClientSocket的setter

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

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

3 个答案:

答案 0 :(得分: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;

当然,它没有编译(我确定,从未尝试过),但这只是一个简短的想法。也许我想念一些事情,如果你有错误可以让我知道。

答案 1 :(得分:0)

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

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

答案 2 :(得分:0)

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

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