Вопрос

Как я могу имитировать OnDestroy Событие для А. TFrame в Delphi?


Я в целом добавил constructor и destructor к моей рамке, думая, что это то, что TForm делает:

TframeEditCustomer = class(TFrame)
...
public
   constructor Create(AOwner: TComponent); override;
   destructor Destroy; override;
   ...
end;

constructor TframeEditCustomer.Create(AOwner: TComponent)
begin
    inherited Create(AOwner);

    //allocate stuff
end;

destructor TframeEditCustomer.Destroy;
begin
   //cleanup stuff

   inherited Destroy;
end;

Проблема с этим заключается в том, что к тому времени, когда мой деструктор работает, элементы управления на раме были разрушены и больше не действительны.

Причина этого находится в деструкуретеру содержащей формы, которую он использует для стрельбы OnDestroy мероприятие:

destructor TCustomForm.Destroy;
begin
   ...
   if OldCreateOrder then DoDestroy; //-->fires Form's OnDestroy event; while controls are still valid
   ...
   if HandleAllocated then DestroyWindowHandle; //-->destroys all controls on the form, and child frames
   ...
   inherited Destroy; //--> calls destructor of my frame
   ...
end;

Разрушетель моего объекта кадров называется, когда проходит деструктор формы. Проблема с этим - это слишком поздно. Форма звонков DestroyWindowHandle, который просит Windows уничтожить рукоятку окна формы. Это рекурсивно разрушает все детские окна - в том числе на моем кадре.

Поэтому, когда моя рамка destructor Запускается, я пытаюсь получить доступ к элементам доступа, которые больше не в действительном состоянии.


Как я могу имитировать OnDestroy Событие для А. TFrame в Delphi?

Смотрите также

Это было полезно?

Решение

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

type
  TCpFrame = class(TFrame)
  private
    FOnDestroy: TNotifyEvent;
    procedure WMDestroy(var Msg: TWMDestroy); message WM_DESTROY;
  published
    property OnDestroy: TNotifyEvent read FOnDestroy write FOnDestroy;
  end;

procedure TCpFrame.WMDestroy(var Msg: TWMDestroy);
begin
  if (csDestroying in ComponentState) and Assigned(FOnDestroy) then
    FOnDestroy(Self);
  inherited; 
end;

Это будет работать только в том случае, если рукоятка окна кадра фактически была создана. Там нет другого хорошей точки крючка, поэтому, если вы хотите убедиться, что он всегда называется, вам понадобится установить флаг в Wmdestroy и отступить к вызовам его в деструктор, если это не ударит.

В WM_NCDESTERORE, которые называются в WM_NCDestroy, который называется в WM_NCDestroy, который вызывается после возвращения всех потомков WM_Destroy сообщений, поэтому форма и все его детские ручки все еще должны быть действительными в этой точке (игнорируя любые, которые были освобождены в форме ondestroy) Отказ

Другие советы

Звучит больше OnClose чем OnDestroy.

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

(Это просто идея, но у меня нет времени прямо сейчас, чтобы построить доказательство концепции, но я делюсь тем не менее :)

Если это проблема с ручкой Windows (us), вы должны проверить, вы можете прикрепить указатель обратного вызова оказания Windows ', который вызывается, когда рукопожатие Windows кадра перестает существовать. Возможно, с функцией, как RegisterwaitforsingleObject.

Другой вариант - переопределить AfterConstruction и BeforeDestruction

Что-то вроде этого:

  TMyFrame = class(TFrame)
  private
    FOnCreate: TNotifyEvent;
    FOnDestroy: TNotifyEvent;
  protected
    procedure DoCreate; virtual;
    procedure DoDestroy; virtual;
  public
    procedure AfterConstruction; override;
    procedure BeforeDestruction; override;
    property OnCreate: TNotifyEvent read FOnCreate write FOnCreate;
    property OnDestroy: TNotifyEvent read FOnDestroy write FOnDestroy;
  end;

  implementation

  procedure TMyFrame.AfterConstruction;
  begin
    inherited;
    DoCreate;
  end;

  procedure TMyFrame.BeforeDestruction;
  begin
    inherited;
    DoDestroy;
  end;

  procedure TMyFrame.DoCreate;
  begin
    if Assigned(FOnCreate) then
      FOnCreate(Self);
  end;

  procedure TMyFrame.DoDestroy;
  begin
    if Assigned(FOnDestroy) then
      FOnDestroy(Self);
  end;
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top