views:

181

answers:

1

I have a TListView descendant which introduces additional features like sorting and loading from a dataset.

I now wish to modify the class so that whenever an item is checked or unchecked it is added or removed in an internal list of checked items so that an application using an instance of the component can easily read the number and location of checked items without having to iterate over all the items in the list view.

Unfortunately, rather than abstracting handling of the check/uncheck operation into some internal method (like DoCheck) that I could override, TCustomListView seems to embed the check logic deep in a large message-handling function.

The only way I can think of to introduce my own behavior neatly into the component is to hijack the OnItemChecked property, causing that property to read and write FOnItemCheckedUser (for example) rather than FOnItemChecked, put my own code in FOnItemChecked, and call FOnItemCheckedUser from my code.

Is there a more straightforward way to handle this? If not, is my idea feasible and safe to implement?

+3  A: 

It's unfortunate that the check-event code is buried in a message handler, but it's not a showstopper. Catch and handle that same message yourself. Detect the same conditions the parent class's message handler checks for, and then do your custom actions there. Afterward, call inherited.

type
  TListViewDescendant = class(TListView)
  private
    procedure CNNotify(var Message: TMessage); message cn_Notify;
  end;

procedure TListViewDescendant.CNNotify(var Msg: TMessage);
begin
  if IsCheckBoxNotification(Msg) then
    DoSpecialCheckBoxHandling;
  inherited;
end;
Rob Kennedy
Thanks, Rob, it took me a couple of days to get back to this. The procedure that handles the CN_NOTIFY message is private and non-virtual in the ancestor class (TCustomListView). I can't override it directly but, presumably, can mask it with my own method to handle CN_NOTIFY. However, I also don't seem to be able to call the ancestor method with inherited — "Cannot access private symbol TCustomListView.CNNotify".
Larry Lustig
Okay, figured out (ie, looked up) how to promote CNNotify to protected in my descendant class, and that seems to allow me to call the inherited version. Currently working away on this.
Larry Lustig
You don't need to override anything. Write your own message handler. Use the `message` directive. The ancestor method doesn't need to be visible. Use just a bare `inherited;` statement and the compiler will forward the message to the next handler, no matter what the next handler happens to be named. (`CNNotify` is just a convention. It can be named anything.)
Rob Kennedy
Got it working now. Only problem is that the code in the inherited message handler fires the OnItemChecked event when just drawing the list view, but that's not coming out of my code. Again, thanks for the help.
Larry Lustig