我有一个 TUpDown 控件,其 Associate 设置为 TEdit 子类的实例。编辑类在其重写的 DoEnter 方法中调用 RecreateWnd。不幸的是,这会在 API 级别杀死伙伴连接,从而导致奇怪的行为,例如单击向上箭头时。
我的问题是编辑实例不知道它是应该重新连接的某个 updown 的伙伴,并且 updown 没有收到失去其伙伴的通知。有什么想法可以重新连接两者吗?
我注意到 TCustomUpDown.SetAssociate 如何检查 updown 和 buddy 是否具有相同的父级,并使用它来避免重复关联。所以我尝试调用我自己的 RecreateWnd 方法:
procedure TAlignedEdit.RecreateWnd;
var
i: Integer;
c: TControl;
ud: TCustomUpDown;
begin
ud := nil;
for i := 0 to Pred(Parent.ControlCount) do
begin
c := Parent.Controls[i];
if c is TCustomUpDown then
if THACK_CustomUpDown(c).Associate = Self then
begin
ud := TCustomUpDown(c);
Break;
end;
end;
inherited RecreateWnd;
if Assigned(ud) then
begin
THACK_CustomUpDown(ud).Associate := nil;
THACK_CustomUpDown(ud).Associate := Self;
end;
end;
et voila - 它有效!
你发现了一些相当不幸的事情。您在应用程序级别设置了两个控件之间的关联,因此您应该能够继续在应用程序级别代码中管理该关联,但 VCL 不提供维护它所需的框架。理想情况下,会有一个通用的关联框架,因此关联的控件可以相互通知他们应该更新自己。
VCL 有这方面的开始,使用Notification
方法,但只通知组件被销毁。
我认为您提出的解决方案对任务来说有点过于具体。编辑控件不一定知道它附加到上下控件,即使知道,也不应该要求它们共享父控件。另一方面,为这个问题编写一个完整的通用观察者框架将是矫枉过正。我提议妥协。
从编辑控件上的新事件属性开始:
property OnRecreateWnd: TNotifyEvent read FOnRecreateWnd write FOnRecreateWnd;
然后像上面那样覆盖RecreateWnd
,但不是所有特定于上下控制的代码,只需触发事件:
procedure TAlignedEdit.RecreateWnd;
begin
inherited;
if Assigned(OnRecreateWnd) then
OnRecreateWnd(Self);
end;
现在,在您的应用程序代码中处理该事件,您可以确切地知道哪些控件相互关联,因此您不必搜索任何内容,也不需要任何父子关系:
procedure TUlrichForm.AlignedEdit1RecreateWnd(Sender: TObject);
begin
Assert(Sender = AlignedEdit1);
UpDown1.Associate := nil;
UpDown1.Associate := AlignedEdit1;
end;
尝试在调用 RecreateWnd 之前将 Associate 属性的值存储在局部变量中,然后再将其设置回来。