SaintJimmy
Member
- Joined
- Jul 7, 2006
- Messages
- 24
- Programming Experience
- 5-10
I've got this application I'm working on, and there's a little annoyance I'm having with the damned ListView control. Here's basically what I've got:
The application is a client program that downloads data from SQL Server and stores it in a local DataSet. I query a customer table and populate a ListView control (lvCustomerList in the code below) with that data, and I have a panel on the form with several controls that display data related to the customer that is currently selected in the ListView control. The user can make changes to the data, and those changes are stored in the local DataSet.
Now... when the user selects a new customer from the ListView, I do some validation in the SelectedIndexChanged event (which I set up using AddHandler in the Form's Load event) to determine if any data was changed, and if it was, I prompt the user to save or reject the changes... and there's an option to cancel and remain on the customer that was changed so they can double-check their entry if they need to.
My problem comes in when the user selects "Cancel" from the prompt. I get the prompt twice when Cancel is selected, and I think it may have something to do with my changing the selection in the cancel routine, even though I remove the handler before changing selection and then add it back after changing.
And to make matters more confusing... when I use the debugger and step through the event handler, I only get the prompt once. Go figure.
Any thoughts on this? I've put the entire SelectedIndexChanged event below for you guys to check out. It's commented out the ass, so you should be able to make sense of what I'm doing. Let me know if I'm doing something wrong here... I've been racking my brain on this for days.
The application is a client program that downloads data from SQL Server and stores it in a local DataSet. I query a customer table and populate a ListView control (lvCustomerList in the code below) with that data, and I have a panel on the form with several controls that display data related to the customer that is currently selected in the ListView control. The user can make changes to the data, and those changes are stored in the local DataSet.
Now... when the user selects a new customer from the ListView, I do some validation in the SelectedIndexChanged event (which I set up using AddHandler in the Form's Load event) to determine if any data was changed, and if it was, I prompt the user to save or reject the changes... and there's an option to cancel and remain on the customer that was changed so they can double-check their entry if they need to.
My problem comes in when the user selects "Cancel" from the prompt. I get the prompt twice when Cancel is selected, and I think it may have something to do with my changing the selection in the cancel routine, even though I remove the handler before changing selection and then add it back after changing.
And to make matters more confusing... when I use the debugger and step through the event handler, I only get the prompt once. Go figure.
Any thoughts on this? I've put the entire SelectedIndexChanged event below for you guys to check out. It's commented out the ass, so you should be able to make sense of what I'm doing. Let me know if I'm doing something wrong here... I've been racking my brain on this for days.
VB.NET:
Private Sub lvCustomerList_SelectedIndexChanged(ByVal sender As System.Object, _
ByVal e As System.EventArgs)
' Dump some data to the Output window to determine what the **** is going
' on here
Debug.WriteLine("Entered handler...")
Debug.IndentLevel += 1
Debug.WriteLine("Selected Index Changed... ")
Debug.IndentLevel += 1
If lvCustomerList.SelectedItems.Count > 0 Then
Debug.WriteLine("Customer Selected: " & _
DirectCast(lvCustomerList.SelectedItems(0), _
CustomerListViewItem).GetDataRow.Item("CustomerName").ToString.Trim())
If Not _currentcustomerrecord Is Nothing Then
Debug.WriteLine("Previous Customer: " & _
_currentcustomerrecord.Item("CustomerName").ToString.Trim())
Else
Debug.WriteLine("First Selection after Execution")
End If
Else
Debug.WriteLine("No items selected")
End If
Debug.IndentLevel -= 1
' There should only be one item selected, since the MultiSelect property
' has been turned off. However, events are also fired when deselecting an item,
' so, check that there is a selected item before proceeding
If lvCustomerList.SelectedItems.Count > 0 Then
' We need to check the current customer record for a value before
' attempting to validate. We only need to validate if this is a
' non-Nothing value, since otherwise it is the first selection made
' upon running the application.
If Not _currentcustomerrecord Is Nothing Then
' If we make it here, then a customer was already selected before
' the index change. Let's verify that the new selection is actually
' a different customer
' We need to be able to gain access to the DataRow associated with
' the newly selected item, so cast the currently selected item to the
' necessary type.
Dim newitem As CustomerListViewItem = _
DirectCast(lvCustomerList.SelectedItems(0), CustomerListViewItem)
' Get the customer number for both the previously selected item
' and the newly selected item
Dim PrevItem As String = _
_currentcustomerrecord.Item("CustomerNumber").ToString
Dim NextItem As String = _
newitem.GetDataRow.Item("CustomerNumber").ToString
' If both items refer to the same customer, then we do not need to
' do anything further. The associated data is still shown in the
' customer data panel, and no save prompt is required.
If PrevItem = NextItem Then
Debug.IndentLevel -= 1
Debug.WriteLine("Exiting hander...")
Exit Sub
End If
' However, if the newly selected item is different, we need to determine
' if any data associated with the previously selected customer has
' changed. If it has, let's prompt the user for some saving instructions.
If CLIDDataSet.HasChanges Then
Debug.WriteLine("Records were changed... prompting.")
' We have some changes to deal with. We need to ask the user what
' to do with them
Dim dresult As DialogResult = _
MessageBox.Show("Save changes to " & _
_currentcustomerrecord.Item("CustomerName").ToString.Trim() & _
"?", "Save changes?", MessageBoxButtons.YesNoCancel, _
MessageBoxIcon.Question)
Select Case dresult
Case DialogResult.OK
' The user wants to save the data, use DataAdapters to
' merge changes to the database on the server.
Debug.WriteLine("Saving changes...")
Case DialogResult.No
' The user wants to discard changes.
Debug.WriteLine("Rejecting changes...")
CLIDDataSet.RejectChanges()
Case DialogResult.Cancel
' The user wants to cancel the prompt. In this case, we
' want to move the selection back to the previous one.
' This is where it gets tricky.
Debug.WriteLine("Cancelled... remain on initial customer")
' We want to make sure that when we move the selection, we
' don't raise another index change event, so temporarily
' remove the SelectedIndexChanged handler
RemoveHandler lvCustomerList.SelectedIndexChanged, _
AddressOf lvCustomerList_SelectedIndexChanged
Debug.WriteLine("Killed selection handler...")
' Now we cancel the selection on the newly selected item
Debug.Write("Deselected new item...")
Debug.WriteLine(newitem.GetDataRow.Item("CustomerName").ToString.Trim)
newitem.Selected = False
' And set selection back to the previously selected item.
' To do this, we need to iterate through all items until
' we find the one with an underlying DataRow that matches
' the current customer record.
For Each itm As ListViewItem In lvCustomerList.Items
' We need to cast to our inherited item class so we
' can access the DataRow
Dim castitm As CustomerListViewItem = _
DirectCast(itm, CustomerListViewItem)
If castitm.GetDataRow.Equals(_currentcustomerrecord) Then
' We've found our item. Select it, and make sure
' the list is scrolled so that it's visible
Debug.Write("Select initial item... ")
Debug.WriteLine(castitm.GetDataRow.Item("CustomerName").ToString.Trim)
castitm.Selected = True
castitm.EnsureVisible()
' There will only be one, so no need to check the
' others.
Exit For
End If
Next
' Now our selections should be correct. Add the handler
' back so that subsequent selection changes will be handled
Debug.WriteLine("Reapplying handler...")
AddHandler lvCustomerList.SelectedIndexChanged, _
AddressOf lvCustomerList_SelectedIndexChanged
' The data panel should still be populated with data for
' the customer that is now re-selected. No other processing
' needed.
Debug.IndentLevel -= 1
Debug.WriteLine("Exiting handler...")
Exit Sub
End Select
End If
End If
btnIPAddRemove.Enabled = True
Dim custitm As CustomerListViewItem
custitm = DirectCast(lvCustomerList.SelectedItems(0), CustomerListViewItem)
_currentcustomerrecord = custitm.GetDataRow()
AppStatus.Text = "Current selection: " & _
custitm.GetDataRow.Item("CustomerName").ToString
Debug.WriteLine("Populating customer data for " & _
custitm.GetDataRow.Item("CustomerName").ToString.Trim)
' Populate the "Network Info" (Notes) textbox
UpdateNotes(custitm.GetDataRow)
' Update the contents of the Contact Info panel
UpdateContacts(custitm.GetDataRow)
' Update the contents of the IP Info panel
UpdateIPInfo(custitm.GetDataRow)
' Update the contents of the Antenna Info panel
UpdateAntennaInfo(custitm.GetDataRow)
Else
' If there is no customer selected, we need to disable the add and
' remove buttons for IP address and MAC address.
If _currentcustomerrecord Is Nothing Then
btnIPAddRemove.Enabled = False
btnAddMAC.Enabled = False
btnRemoveMAC.Enabled = False
End If
End If
Debug.IndentLevel -= 1
Debug.WriteLine("Exiting handler...")
End Sub