2

I am trying to dynamically add actionitems, I can add the item and it works when I do this:

HostActionItem := ActionManager.ActionBars[0].Items[0].Items[2];
  NewItem := HostAction.Items.Add;
  NewItem.Action :=  MyActionToPerform;
  NewItem.Caption := Description;
  NewItem.ImageIndex := 1;
  NewItem.Tag := 13;

However, when the action Execute method fires I attempt to get the ActionComponent from the Sender object like this:

  if (Sender is TAction) then
  tag := (Sender As TAction).ActionComponent.Tag;

But the ActionComponent is always nil. Why is the ActionComponent not being initialised?

menjaraz
  • 7,551
  • 4
  • 41
  • 81
Leigh S
  • 1,837
  • 11
  • 17
  • 1
    _"Why is the ActionComponent not being initialized?"_ seems to be the real question here, instead of how to add actions to an action manager. By the way, try using the action `Tag` and if you need different tags for the same action, that maybe symptom you need another action, instead of creating a ["god" event handler](http://en.wikipedia.org/wiki/God_object). – Trinidad Nov 26 '10 at 18:44
  • Sorry to confuse the question by phrasing it the way I have. Essentially you are correct. I am chasing a way of having dynamic actions and therefore need a fairly flexible event handler. Do you suggest creating the underlying actions dynamically as well or is there a better way to be doing this? – Leigh S Nov 27 '10 at 08:29

1 Answers1

5

short answer:

You're expecting a TActionClientItem to show up as ActionComponent of an TAction. That won't happen since TActionClientItem does not descend from TComponent.

longer answer:

I believe you're adding your item to a menu bar. It seems to be by design that an TAction linked to a menu item would not support the ActionComponent. The items of a menu bar is of type TActionClientItem. This is a 'collection item', not a 'component'. Hence the menu cannot fill in the ActionComponent parameter with the menu item when calling the Execute method of the action link of the selected item. If this sounds confusing, I guess the below quotes from the VCL source would make it clear:

TBasicActionLink.Execute method:

function Execute(AComponent: TComponent = nil): Boolean; virtual;

The passed component is assigned to FAction.ActionComponent before it is executed.

How it's called from TCustomActionMenuBar.ExecAction:

FSelectedItem.ActionLink.Execute;

For the question in the title, I don't think you're doing anything wrong, apart from setting the Caption and ImageIndex of a TActionClientItem is unnecessary, as it's the TAction's title and image which will be shown.

bluish
  • 26,356
  • 27
  • 122
  • 180
Sertac Akyuz
  • 54,131
  • 4
  • 102
  • 169
  • Thanks for the answer. I set the caption, imageindex & tag because I re-use the same action for multiple action links. Am I doing this the hard way? Is there a better way of trying to achieve dynamic action items? – Leigh S Nov 27 '10 at 08:31
  • @Leigh - I don't see any easier way.. add a client item and associate it with an action, that's about it. Note that if you reuse actions you won't be able to offer the built-in customization ability. And if you need to differentiate the source in OnExecute, the only way seems to be to use an action per item. – Sertac Akyuz Nov 27 '10 at 13:14
  • Thanks, I now just maintain separate actions for the dynamically created items and it works fine. – Leigh S Nov 29 '10 at 01:25