2016-10-10 2 views
3

В режиме исполнения только пакет, я определил TFrame потомка, который публикует OnLoaded событие:Как правильно опубликовать мероприятие?

type 
    TMyMethod = procedure() of object; 

    TMyFrame = class(TFrame) 
    protected 
    FOnLoaded : TMyMethod; 
    procedure Loaded(); override; 
    published 
    property OnLoaded : TMyMethod read FOnLoaded write FOnLoaded; 
    end; 

implementation 

{$R *.dfm} 

procedure TMyFrame.Loaded(); 
begin 
    inherited; 
    if(Assigned(FOnLoaded)) 
    then FOnLoaded(); 
end; 

В DesignTime только пакет, я зарегистрирован компонент TMyFrame следующим образом:

unit uMyRegistrations; 

interface 

uses 
    Classes, uMyFrame; 

procedure Register; 

implementation 

procedure Register; 
begin 
    RegisterComponents('MyTestComponents', [ 
    TMyFrame 
    ]); 
end; 

Я установил пакет времени разработки, я могу найти TMyFrame в палитре инструментов, и его событие OnLoaded отображается в инспекторе объектов.

Я перетащил TMyFrame в форму, после чего я назначил событие OnLoaded двойным щелчком от инспектора объекта. После назначения события я заметил, что при попытке открыть файл формы в Delphi появляется сообщение об ошибке нарушения прав доступа (он позволяет мне открыть файл «.pas», но я не могу переключиться на визуальный дизайнерский вид).

enter image description here

ли я правильно опубликовал OnLoaded событие? Если да, что еще не так?

Дальнейшая информация:

  1. Я использую Delphi 2007 (не знаю, если это имеет значение).
  2. Ошибка также возникает, если сделать то же самое с разными родительскими классами (не только для потомков TFrame).

ответ

8

Обновлено (несколько менее фиктивный) ответ

Вы приняли мой первоначальный ответ, но то, что я написал не правильно. Роб Кеннеди указал на article бывшего разработчика Embarcadero Аллена Бауэра на тему Assigned.

Аллен объясняет, что функция Assigned проверяет только один указатель на два указателя указателя метода. IDE во время разработки использует это, присваивая значения дозорных значений любым опубликованным свойствам метода (т. Е. Событиям). Эти контрольные значения имеют nil для одного из двух указателей указателя метода (тот, который проверяет Assigned) и индекс, идентифицирующий значение свойства в другом указателе.

Все это означает, что False возвращается, когда вы вызываете Assigned во время разработки. Пока вы проверяете опубликованные указатели методов с Assigned перед их вызовом, вы никогда не будете называть их во время разработки.

То, что я изначально написал, не может быть правдой.

Так что я вырыл немного глубже. Я использовал следующий очень простой код, тестирование с XE7:

type 
    TMyControl = class(TGraphicControl) 
    protected 
    FSize: Integer; 
    procedure Loaded; override; 
    end; 

.... 

procedure TMyControl.Loaded; 
begin 
    inherited; 
    FSize := InstanceSize; 
end; 

.... 

procedure Register; 
begin 
    RegisterComponents('MyTestComponents', [TMyControl]); 
end; 

Этого было достаточно, чтобы вызвать AV в IDE во время разработки, когда метод Loaded был выполнен.

Мое заключение заключается в том, что среда IDE делает некоторые вещи с более сложными вещами при потоковой передаче, а ваши объекты не находятся в состоянии пригодности для использования при вызове метода Loaded. Но у меня нет лучшего понимания.


Оригинал (очень обманчиво) ответ

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

Код элемента управления доступен, IDE загрузил его, но код, который реализует обработчик событий, не является. Этот код не является частью пакета времени разработки, он является частью проекта, который в настоящее время открыт в среде IDE. В конце концов, это может даже не скомпилировать!

Метод Loaded должен защититься от этого, как так:

procedure TMyFrame.Loaded(); 
begin 
    inherited; 
    if not (csDesigning in ComponentState) and Assigned(FOnLoaded) then 
    FOnLoaded(); 
end; 
+2

Параметр 'Функция Assigned' должна защищать против этого уже. [Во время разработки среда IDE назначает обработчик события специальному значению, поэтому он знает, что писать в ресурсе DFM, но это 'Assigned' будет считаться неназначенным.] (Http://community.embarcadero.com/blogs/entry/assign-or-not-assign-that-is-the-question-28836) Если только что-то особенное об увольнении обработчиков событий из «Loaded», я думаю, что в этом вопросе больше. –

+0

@RobKennedy Я думаю, что вы правы, большое вам спасибо. Я думаю, что происходит нечто большее. Я не могу полностью объяснить это, но я могу воспроизвести проблемы из метода Loaded без каких-либо тестов для 'Assigned' и без указателей на методы. –

+0

Я принял ваш ответ, потому что добавление условия «не (csDesigning в ComponentState)» разрешило ошибку AV, и я подумал, что это была основная причина, по которой у меня был AV во время разработки. Согласно вашему обновленному ответу, условие «Назначено (...)» достаточно для «нормальных» событий. Я проверил событие TCustomForm.DoShow, и я могу подтвердить, что вы сказали, он запускает событие OnShow, подобное этому: «Если назначено (FOnShow), то FOnShow (Self);». Я задам конкретный вопрос о выполнении событий из таких методов, как Loaded. Спасибо, что вы обновили свой ответ. – ExDev