Delphi TAction.OnUpdate事件是否会降低性能?

Delphi TAction.OnUpdate事件是否会降低性能?,delphi,delphi-xe7,tlistview,taction,Delphi,Delphi Xe7,Tlistview,Taction,在Delphi XE7中,我使用此技巧根据是否选择ListView中的项目自动启用或禁用工具栏按钮(“编辑ListView项目”),以防止用户在没有选择ListView项目的情况下单击按钮: 在VCL表格上放一个战术专家 在操作列表中创建操作actTest 在表格上按一个T按钮 将动作actTest分配给按钮 在表单上放置一个TListView 在ListView中创建两个项目 在actTest操作写入的OnUpdate事件中: procedure TForm1.actTestUpdate(

在Delphi XE7中,我使用此技巧根据是否选择ListView中的项目自动启用或禁用工具栏按钮(“编辑ListView项目”),以防止用户在没有选择ListView项目的情况下单击按钮:

  • 在VCL表格上放一个战术专家
  • 在操作列表中创建操作
    actTest
  • 在表格上按一个T按钮
  • 将动作
    actTest
    分配给按钮
  • 在表单上放置一个TListView
  • 在ListView中创建两个项目
  • actTest
    操作写入的
    OnUpdate
    事件中:

     procedure TForm1.actTestUpdate(Sender: TObject);
     begin
       actTest.Enabled := ListView1.SelCount > 0;
       CodeSite.Send('actTestUpdate'); // gets fired very often!
     end;
    
现在您可以看到,按钮的启用或禁用取决于是否选择了ListView中的某个项目,而与使用鼠标、键盘或编程方式选择/取消选择项目无关

但是,在CodeSite Live Viewer中,我可以看到,
actTestUpdate
事件是连续且经常触发的,因此语句
actTest.Enabled:=ListView1.SelCount>0经常被执行


所以我的问题是:这会降低性能吗?如果是,是否还有其他技巧可以达到上述目的?

操作更新事件(主要)在Application.Idle内执行。只要不在事件处理程序中执行时间关键的操作,就不会出现明显的性能下降。

通常 是的,事件处理程序需要时间,就像任何其他例程一样。多个处理程序占用该时间的倍数。所有这些代码的总量将评估导致无所事事的条件。从这个意义上讲,您可以得出这样的结论:这种更新机制会降低性能。特别是考虑到这些更新事件经常发生:

在应用程序空闲或操作列表更新时发生

这可能是不使用它的一个理由。但是您应该意识到,对单个表达式的求值通常不会花费那么多时间。另外,要认识到,无论动作更新如何,应用程序都会在每次鼠标移动时执行(更繁重的)计算和操作

当您将操作更新事件中的代码持续时间保持在最小值(例如,不通过数据库连接检查密码)时,性能将正常。如果您有与更新操作相关联的冗长操作,那么在这些特定情况下,您可以求助于手动更新

请注意,不使用操作的单个
OnUpdate
事件,而是使用操作列表的事件,可以稍微提高性能,该事件具有
Handled
参数以取消进一步的处理,并具有集中和分类的额外好处

明确地 您的
ListView1.SelCount
向控件发送一条WinAPI消息以检索选择计数。这是一个很小的手术,我不会打扰它所需要的时间

另一种方法是更新ListView事件中的操作。该事件将捕获由于鼠标和键盘交互而导致的所有选择更改,以及设置单个项目的属性 财产:

procedure TForm1.ListView1SelectItem(Sender: TObject; Item: TListItem;
  Selected: Boolean);
begin
  actTest.Enabled := ListView1.SelCount > 0;
end;
但是,ListView和VCL都不提供仅在
SelCount=0
SelCount>0
之间发送信号的任何内容,因此您将更严格地评估该行代码

假设
MultiSelect
为真,您也可以自己计算选择更改,以消除调用
SelCount
的需要:

  private
    FListViewSelected: Longbool;

procedure TForm1.ListView1SelectItem(Sender: TObject; Item: TListItem;
  Selected: Boolean);
begin
  if Selected then
    Inc(FListViewSelected)
  else
    Dec(FListViewSelected);
  actTest.Enabled := FListViewSelected;
end;
或所选项目的测试为零:

procedure TForm1.ListView1SelectItem(Sender: TObject; Item: TListItem;
  Selected: Boolean);
begin
  actTest.Enabled := ListView1.Selected <> nil;
end;
如果您有(或计划有)多个操作,您可能希望将Application.ActionUpdateDisplay设置为例如50毫秒。这可以提高性能


同样,如果您有许多操作,我建议您尝试使用TForm.UpdateActions,而不是为每个操作定义TAction.OnUpdate。这将使代码更具可读性。

更新的
traction.OnUpdate
目的是做你正在做的事情,看看你是按照预期做的。但是,这是不必要的资源浪费。更糟糕的是,可能有一些情况需要在方法执行过程中禁用某个动作,并且使用<代码> OnUpvest方法可能导致不安全地延迟。我试图完全避免个人更新。@TLama您建议哪种选择?我会在发生事情时立即更新操作状态。在这种情况下,当列表视图的基础模型选择发生更改时。@TLama您会怎么做?我都试过了。记住,目标是独立于使用鼠标或键盘选择/取消选择项目来更新按钮。这与时间关键性无关(事情本身取决于时间花费),而是与时间花费/持续时间有关(事情本身对未来的事情有影响)。NGLN,如果您提供了一个没有缺陷的
OnSelectItem
工作示例,我将推荐您参加下一届诺贝尔奖。我已经试过了…@user你了解OnIdle吗,当它启动时,为什么会影响OnUpdate?是的,这就是问题所在,不过我会选择更高的值。
procedure TForm1.ActionList1Update(Action: TBasicAction; var Handled: Boolean);
begin
  actTest.Enabled := ListView1.Selected <> nil;
  Handled := True;
end;