Thanks for your help guys, I managed to resolve the problem.
There were 2 issues causing the slowness.
1) It was changing the colour of the items in the list box based on their status, the status was calling a method that used prices and costs, the price logic was taking a couple of seconds per item which added up to minutes once the number of items increased.
2) It was rebuilding the full list of items on the tile when the notification occured which meant the new items were in the correct sort order, but also took more time. I changed it to just add a new item to the list box, which means it shows at the bottom of the list and is not in its sorted position, but it saves heaps of time. The user can always press the re-sort button if they want the new items sorted. Also, I remove items individually from the list box on a tile.
As others stated, investigating what the userNotify code does when receiving the notification is normally the best place to start when you're noticing performance issues around notifications. However, you do still need to keep in mind that a very large flood of notifications could still produce an unresponsive application whilst it is processing those notifications, particularly if each notification results in changes to the UI. To that end, even though you've solved the immediate problem I will make the following comment about the example code as well:
I have used beginNotification on the control, specifying the currently logged in User object and an event number.
eg. beginNotification(app.myCurrentUser, 6004, Response_Continuous, 0);
The control has a userNotify method that calls a method to rebuild the list on the control.
When a price event occurs I call a causeEvent method.
eg. oUser.causeEvent(6004, false, oUser);
Since a single price change can cause multiple events I cause each event as 'non-immediate', then run a begin/commit transaction after they are all banked up.
eg. foreach oUser in oGroup.allMembers discreteLock do
oUser.causeEvent(6004, false, oUser);
oUser.causeEvent(6012, false, oUser);
endforeach;
if not process.isInTransactionState() then
beginTransaction;
commitTransaction;
endif;
Doing 2 causeEvents for each user in oGroup.allMembers won't necessarily scale very well as you add more and more users to the group as each user added to the group means more notifications to be distributed. If the system is only ever going to have a very small number of users in a group, then that's probably not of concern but if you could potentially have thousands of users in a group that's thousands of causeEvents being individually generated. A better approach would be to register for the notifications and do the causeEvents against a much smaller number of objects. For example, a common approach is to do the notifications against the "system" object, as then you're only doing causeEvents for a single object. In that case, there would be only two causeEvents issued per price change irrespective of the number of members in the group, rather than 2 x number of members in the group that the current code issues.
Further to this, you may want to consider creating a notification manager that takes care of grouping, dropping duplicates, and eventually sending the causeEvents. This allows you to handle the situation of an update that affects only a single price, versus an update that affects say 30 prices, still only issuing 2 causeEvents even when you update 30 prices in one go rather than 60 causeEvents, or 60 * number of members as happens with the current code. For a group with say 2,000 members, that would mean you go from issuing 2 * 2000 * 30 = 120,000 causeEvents to issuing only 2 causeEvents, thereby significantly reducing the load on the system. You would also be able to remove that horrible kludgy code that is checking process.isInTransactionState...
Cheers,
BeeJay.