Why do I get this error msg: Undec开发者_开发知识库lared identifier: 'OnClick'
I'm using Delphi 7 and here's my complete code:
procedure TForm1.Button1Click(Sender: TObject);
var
SavedOnClick : TNotifyEvent;
begin
SavedOnClick := TControl(Sender).OnClick;
try
// Code which takes some time
finally
TControl(Sender).OnClick := SavedOnClick;
end;
end;
When casting, use TButton
instead of TControl
. The OnClick
property of the TControl
is protected.
If you look at TControl the OnClick property is defined as protected. IE it is not visible except to descendant classes. There are two simple ways around this, first would be to use TButton(Sender).OnClick the second would be to create a hack class that you can use to get to the property:
type
TControlOnClickHack = class(TControl)
published
property OnClick;
end;
Then use TControlOnClickHack(Sender).OnClick
Warning, make sure your senders have an onClick event before you decide to use the later idea. TypInfo supplies a function called IsPublishedProp that would be a good idea to use before you attempt to unset/set the property.
Declare a class that extends TControl in the same unit as the code that wishes to access the protected members (OnClick is protected in TControl).
Since the new class is in the unit, we have direct access to it's protected members from other classes in that same unit. it doesn't (and I would say "shouldn't") need to be in the interface as it is strictly an implementation detail of your unit:
unit ... ;
interface
:
implementation
:
type
TControlHelper = class(TControl);
// Now we can type-cast to the "helper" class to gain access
// to the protected members of the ancestor:
procedure TForm1.Button1Click(Sender: TObject);
var
SavedOnClick : TNotifyEvent;
begin
if Sender is TControl then
SavedOnClick := TControlHelper(Sender).OnClick;
try
// Code which takes some time
finally
if (Sender is TControl) then
TControlHelper(Sender) := SavedOnClick;
end;
end;
Notice that when checking the type of Sender we check for an instance of the desired ancestor class since it will not ever be an instance of our helper class itself. Any object that is a TControl can be safely accessed as a TControlHelper, regardless of what actual derived class it may be an instance of.
For this reason I disagree that this is a "hack", as that has negative connotations that I don't think should apply - nothing here is unsafe or liable to break. It is a technique that takes advantage of language features, nothing more.
NOTE: I called this class TControlHelper but it is NOT a "class helper" as defined and implemented in Delphi 2007 (?) and later, although it has about 90% in common in terms of what you can achieve and in fact imho is safer than those "real" helpers.
Also you can clean up the typecasting by exploiting the absolute keyword, as long as you keep the type checking in place this is perfectly (well, just as safe as hard casting), functionally identical and much cleaner to read imho:
procedure TForm1.Button1Click(Sender: TObject);
var
control: TControlHelper absolute Sender;
SavedOnClick : TNotifyEvent;
begin
if Sender is TControl then
SavedOnClick := control.OnClick;
try
// Code which takes some time
finally
if (Sender is TControl) then
control.OnClick := SavedOnClick;
end;
end;
精彩评论