Как имитировать мероприятие OnDestroy на Tfraame в Delphi?
-
09-10-2019 - |
Вопрос
Как я могу имитировать 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;