Реагирование на связанные события компонента Delphi - PullRequest
0 голосов
/ 13 января 2010

У меня есть пользовательский компонент (вырублено)

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

Прямо сейчас у меня в событии OnConnect ClientSocket Call ClientConnected, например,

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

Есть ли способ сделать это в классе TMyComponent без необходимости внешнего события?

Edit:
Забыл сказать, что 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;

Но я чувствую, что он снова будет преследовать меня ...

Ответы [ 3 ]

1 голос
/ 22 января 2010

Что нужно для успешного перехвата событий для назначенного 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;

Конечно, он не компилируется (я уверен, никогда не пробовал), но это всего лишь краткое изложение идеи. Может быть, я что-то упустил, дайте мне знать, если у вас есть ошибки, чтобы сделать отзыв.

0 голосов
/ 13 января 2010

Возможно, вы переопределяете класс TClientSocket, и в том месте, где вызывается событие, вы также вызываете собственную подпрограмму. Единственная загвоздка в том, что вам нужна подпрограмма, помеченная как виртуальная или динамическая, чтобы сделать это переопределение, и я не проверял, выполняет ли это TClientSocket.

В этом случае вы все равно можете выставить клиентский сокет как TClientsocket, как и при необходимости.

0 голосов
/ 13 января 2010

Да, вы можете просто реализовать процедуру с этой подписью в своем компоненте и назначить ее событию при создании TClientSocket.

ОДНАКО ... поскольку вы открываете ClientSocket, это означает, что можнопереписать это назначение события из кода, используя ваш компонент.В зависимости от порядка, в котором происходят события, и от того, кто будет использовать ваш компонент, это может быть не проблемой для вас, но вы можете подумать о том, чтобы сделать ClientSocket частным или защищенным, или, возможно, написать простой прокси-сервер, который вы затем используете дляубедитесь, что ваш ClientConnected вызывается перед обработчиком событий пользователя.

...