28 March 2009

The ListItems Collection (1)

Recent posts discuss the underlying implementation of the Collection Ocx object. I pointed out that COM (read Microsoft) dictates the properties and methods and the number and type of parameters used to invoke them. In short, a collection is a COM object with a limit set of prededicated members, where the member type is a Variant. In the same style VB/COM introduced collections to provide as a means to access items of a control. In early Windows only the standard controls ListBox and ComboBox provided a user interface to access an item from a list of strings. For these controls COM/VB doesn't provide a collection to set and get a given item. Both COM controls included the following properties and methods to manage the entries in the control: .AddItem .RemoveItem .List(index) .ListCount Knowing everything about the Collection object now, you will immediately see the resemblence with the Collection objects properties and methods: .Add .Remove .Item(index) .Count When it came to create COM wrappers for the common controls introduced with Windows 95 like ListView, TreeView, ToolBar, StatusBar, and ImageList, the VB creators thought about abstracting the items of a control by introducing Collections. The elements of these controls were now to be accessed like the mother of all collections, the Collection object. Whenever a control hasn't a fixed number of elements it's elements are to be managed by a collection. For a ListView control this meant the introduction of multiple collections to manage the different aspects of the control. For instance, when the ListView is viewed in report or detail view it contains a header control, which required a ColumnHeaders collection. Then there were the items of ListView itself, they were assembled in a ListItems collection. Then there were checked and selected items, they were collected in a CheckedItems and a SelectedItems collection, respectively. Fortunately, the collections ListItems, CheckedItems and SelectedItems are all collections of the same (data) type: the ListItem object. This brings us to the subject of this post. The ListItems collection is a collection of ListItem objects. As any collection it supports - as it should - the well known Collection properties and methods to manage the entries. The ListItems collection is a way to access the ListView items, which are more than simple strings. A ListView item must specify text, an icon, a selected icon, a checked state, a selected state, etc. The windows API describes a ListView item in a LV_ITEM structure (Type). Type LV_ITEM mask As Long iItem As Long iSubItem As Long State As Long stateMask As Long pszText As Long cchTextMax As Long iImage As Long lParam As Long iIndent As Long End Type This API type is connected to the ListItem COM object. Note that ListItems is a collection of objects of this ListItem object. Anything you do using a ListItems collection (Add, Remove, Count, Item) means operating on a ListItem object. For instance, the .Item method returns a ListItem object, and the .Count property returns the current number of ListItem objects. For now and the upcomming post it is important to realize a few things.
  • A ListItem object is directly connected to a LV_ITEM structure. A pointer to the ListItem Ocx object, as it is implemented by GFA-BASIC 32, is stored in the lParam parameter of the LV_ITEM structure.
  • When you add an item to the ListView, a ListItem COM object is created and a pointer is stored in the LV_ITEM structure. Then the LV_ITEM is inserted into the ListView control. The ListItem is NOT added to som internal array of ListItems, because GFA-BASIC doesn't maintain a hash table for the ListItems collections.
  • A ListItems collection object only provides a way to access these items. A ListItems collection is used to count the number of items in a ListView and to obtain and remove a single ListItem object. When you invoke the .Remove method of the ListItems collection the ListView's item is removed and the ListItem COM object stored in the lParam is destroyed.
The ListItems collectection complies to the interface of a Collection Ocx, but it isn't (at all) implemented as a Collection Ocx, as I described in previous posts. There is no underlying hash table where the ListItem objects are stored. The ListItems properties and methods act upon the ListView directly. When ListItems.Count is invoked, the COM object sends the LVM_GETCOUNT message to the ListView control. In the same way, the .Item(index) method of the ListItems collection, sends the LVM_GETITEM and obtains the ListItem object from the lParam member of the LV_ITEM structure. When you use the For Each construct to iterate over the ListView's items, GFA-BASIC sends a LVM_GETITEM for each item currently present in the ListView. As such, the ListItems collection always represent the current state (and thus sort order) of the ListView. This is an important difference with VB, where the ListItems collection is stored separatly (in a hashtable) from the ListView's items. VB must take extra steps to keep the ListItems collection in sync with the actual state of the ListView. A strange design flaw, because after a sort operation VB's ListItems collection is completely out of sync! Next post discusses a custom sort routine for a ListView.

No comments:

Post a Comment