I recently wrote a code conversion project, with a simple windows form to review and adjust the results.  It had a list view container on the left to enumerate the scripts, and two text boxes on the right for the selected script in the list: the top for the original script, and the bottom for the result of the programmatic conversion.  The conversion was 100% correct in about 95% of the scripts, so the human element was needed to catch exceptions that the code converter missed and make adjustments.

I added code in the instantiation method to populate the listview control from its database source.  To save the user unnecessary mouse movement and clicks, I then added code to iterate through each script on the first pass, and convert the script.  This saved the user a few button presses to convert and save, where no script adjustment was needed–the vast majority of cases.  The user, while reviewing scripts, could also reconvert the script with a button press to reset to the original content if any change needed to be reset.

I wrote the load and update methods for the scripts to operate on the currently selected item in the ListView.  So the code to pre-populate the script conversions used the .selected property to select the script to operate on, then called the Load/Convert/Update methods to do the work.  These db-layer methods used the table  identity value, stored in the .Tag property of the item.   Afterwards, the .selected property was set back to false before the next iteration.

The code worked fine when the user would click on an item in the list view, but the initial population would throw an error saying “index out of range”.  I discovered the problem when I single-stepped the code in the pre-population.  While the .selected property of the item was set to true, the .SelectedItems and .SelectedIndices properties both still showed a count of  zero on the next instruction.

I began to recognize that I had a state problem with the ListView object.  While the property is set to true, these other properties are not updated until the method completes, and the windows form thread bubbles its way out of your method through the various wrappers, and returns to an idle state.  The problem is similar to the orphaned tray icon problem (see Preventing the orphaned system tray icon in a Windows App). So to use the ListView as the indexer in my loop, I needed to implement an idle state, and move the work into a timer event. An example of the code is here.

One other approach is to write the GetScript() and UpdateScript() methods for the individual scripts to take the identity value as a parameter.  This would facilitate both a straight index from a loop, and a selected ListViewItem (i.e. passing the stored identity from the .Tag property, etc).  If you plan on doing bulk actions on your items in the ListView manifest, this is a better approach.  But if you are inheriting code that just needs to have bulk actions added where previously only actions on selected items occurred, and the code is highly intertwined, this is a way of using the existing windows control’s selection work when using iteration.