Monday, November 06, 2006

TabControl, ListView and checking list items

Today I found an odd feature with the ListView GUI control. The list view must be the king of Windows controls. I mean, what can't it do? It can display lists in 5 different ways, which is increasing as Windows evolves. It can even display a list with check boxes for each item, very similar to the CheckedListBox. But the ListView behaves very differently when it comes to checking and unchecking list items if it is placed in a TabControl.

The event ItemCheck should be called when the user or code checks an item in the list. But the oddity I found was that the ItemCheck event method would NOT be called when code/user checks a list item, but the event is first called when the user clicked on the tab that contained the control.

This is what I did (
Full source code available at pastebin.com):
  • Created a Form with a ListBox, TabControl and a ListView
  • The TabControl contains 3 tab pages, the initial tab with a button, the second tab with a second ListView and the third tab page contained a CheckedListBox.
  • Added event listeners for all three lists that would add text into the ListBox to show what happens and when.
  • When pressing the button, it will check the first item in all lists (the two ListViews and the CheckedListBox).
This is what I found:
  • When the button was clicked, it would call the ItemCheck method on the CheckedListBox and the ListView outside the tab control. It would NOT call the ItemCheck method on the ListView inside tab page 2. (Form screen shot)
  • When I clicked on tab page 2, then it would call the ItemCheck method on the ListView inside that tab page. (Form screen shot). Somehow the ListView remembered that I wanted some of the items checked.
Now we have two differently behaviours depending if a ListView is inside a tab control or not.
  1. If a ListView is outside a tab control it will call the ItemCheck method when the property is changed. But if the ListView is inside a tab control (that isn't visible) it will not call the ItemCheck method when the property is changed.
  2. A CheckedListBox inside a tab control (not visible) will call the ItemCheck method when the property is changed; and the ListView will not call the ItemCheck method.
Workaround:
In our case I solved it by setting a boolean to false in the TabControl_SelectedIndexChanged() event, and then setting it to true in the TabControl_Selected() event. This way I can check from the boolean if the ItemCheck() comes from the user or is cached by the ListView. If the boolean is true, then I know the user checked a list item.



C'mon, which is the correct behaviour?
Why is there a need for a different behaviour?
Why do I have to bother?

Perhaps I didn't know that it is common GUI-OO design to have one implementation if a control is in a TabControl and one if it isn't.