为什么从代码中调用事件处理程序是不好的做法? [英] Why is it bad practice to call an eventhandler from code?

查看:17
本文介绍了为什么从代码中调用事件处理程序是不好的做法?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设您有一个执行相同任务的菜单项和一个按钮.为什么将任务代码放入一个控件的操作事件中然后从另一个控件调用该事件是不好的做法?Delphi 和 vb6 一样允许这样做,但 realbasic 不允许这样做,并说您应该将代码放入一个方法中,然后由菜单和按钮调用

Say you have a menu item and a button that do the same task. Why is it bad practice to put the code for the task into one control's action event and then make a call to that event from the other control? Delphi allows this as does vb6 but realbasic doesn't and says you should put the code into a method that is then called by both the menu and the button

推荐答案

这是你的程序如何组织的问题.在您描述的场景中,菜单项的行为将根据按钮的:

It's a question of how your program is organized. In the scenario you've described, the menu item's behavior will be defined in terms of the button's:

procedure TJbForm.MenuItem1Click(Sender: TObject);
begin
  // Three different ways to write this, with subtly different
  // ways to interpret it:

  Button1Click(Sender);
  // 1. "Call some other function. The name suggests it's the
  //    function that also handles button clicks."

  Button1.OnClick(Sender);
  // 2. "Call whatever method we call when the button gets clicked."
  //    (And hope the property isn't nil!)

  Button1.Click;
  // 3. "Pretend the button was clicked."
end;

这三个实现中的任何一个都可以工作,但是为什么菜单项应该如此依赖于按钮?按钮有什么特别之处,它应该定义菜单项?如果新的 UI 设计取消了按钮,菜单会发生什么变化?更好的方法是分解事件处理程序的操作,使其独立于它所附加的控件.有几种方法可以做到这一点:

Any of those three implementations will work, but why should the menu item be so dependent on the button? What's so special about the button that it should define the menu item? If a new UI design did away with buttons, what would happen to the menu? A better way is to factor out the event handler's actions so it's independent of the controls it's attached to. There are a few ways to do that:

  1. 一种是完全摆脱 MenuItem1Click 方法,并将 Button1Click 方法分配给 MenuItem1.OnClick 事件属性.为分配给菜单项事件的按钮命名的方法令人困惑,因此您需要重命名事件处理程序,但这没关系,因为与 VB 不同,Delphi 的方法名称不定义它们的事件处理.只要签名匹配,您就可以将任何方法分配给任何事件处理程序.两个组件的 OnClick 事件都是 TNotifyEvent 类型,因此它们可以共享一个实现.为它们的作用命名方法,而不是它们所属的名称.

  1. One is to get rid of the MenuItem1Click method altogether and assign the Button1Click method to the MenuItem1.OnClick event property. It's confusing to have methods named for buttons assigned to menu items' events, so you'll want to rename the event handler, but that's OK, because unlike VB, Delphi's method names do not define what events they handle. You can assign any method to any event handler as long as the signatures match. Both components' OnClick events are of type TNotifyEvent, so they can share a single implementation. Name methods for what they do, not what they belong to.

另一种方法是将按钮的事件处理程序代码移动到单独的方法中,然后从两个组件的事件处理程序中调用该方法:

Another way is to move the button's event-handler code into a separate method, and then call that method from both components' event handlers:

procedure HandleClick;
begin
  // Do something.
end;

procedure TJbForm.Button1Click(Sender: TObject);
begin
  HandleClick;
end;

procedure TJbForm.MenuItem1Click(Sender: TObject);
begin
  HandleClick;
end;

这样,真正起作用的代码不会直接绑定到任何一个组件,并且让您可以更轻松地更改这些控件,例如通过重命名或替换它们具有不同的控件.将代码与组件分离导致我们采用第三种方式:

This way, the code that really does stuff isn't tied directly to either component, and that gives you the freedom to change those controls more easily, such as by renaming them, or replacing them with different controls. Separating the code from the component leads us to the third way:

Delphi 4 中引入的 TAction 组件是专为您所描述的情况而设计的,其中同一命令有多个 UI 路径.(其他语言和开发环境提供类似的概念;它不是 Delphi 独有的.)将您的事件处理代码放在 TActionOnExecute 事件处理程序中,然后分配它按钮和菜单项的 Action 属性的操作.

The TAction component, introduced in Delphi 4, is designed especially for the situation you've described, where there are multiple UI paths to the same command. (Other languages and development environments provide similar concepts; it's not unique to Delphi.) Put your event-handling code in the TAction's OnExecute event handler, and then assign that action to the Action property of both the button and the menu item.

procedure TJbForm.Action1Click(Sender: TObject);
begin
  // Do something
  // (Depending on how closely this event's behavior is tied to
  // manipulating the rest of the UI controls, it might make
  // sense to keep the HandleClick function I mentioned above.)
end;

想要添加另一个类似于按钮的 UI 元素?没问题.添加它,设置它的 Action 属性,你就完成了.无需编写更多代码来使新控件的外观和行为与旧控件相同.您已经编写过该代码一次.

Want to add another UI element that acts like the button? No problem. Add it, set its Action property, and you're finished. No need to write more code to make the new control look and act like the old one. You've already written that code once.

TAction 不仅仅是事件处理程序.它可以让您确保您的 UI 控件具有统一的属性设置,包括标题、提示、可见性、启用和图标.当命令当时无效时,相应地设置操作的 Enabled 属性,任何链接的控件将自动被禁用.例如,无需担心通过工具栏禁用命令,但仍通过菜单启用命令.您甚至可以使用操作的 OnUpdate 事件,以便操作可以根据当前条件更新自身,而不是您需要知道何时发生可能需要您设置 Enabled 立即拥有.

TAction goes beyond just event handlers. It lets you ensure that your UI controls have uniform property settings, including captions, hints, visibility, enabledness, and icons. When a command isn't valid at the time, set the action's Enabled property accordingly, and any linked controls will automatically get disabled. No need to worry about a command being disabled through the tool bar, but still enabled through the menu, for example. You can even use the action's OnUpdate event so that the action can update itself based on current conditions, instead of you needing to know whenever something happens that might require you to set the Enabled property right away.

这篇关于为什么从代码中调用事件处理程序是不好的做法?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆