views:

523

answers:

2

...or are c# listviews really such a nightmare to manage?

Okay the problem I'm working on is very simple. Or at least it appears to be so:

I have a text file which contains information about customer orders on separate lines. The data items are separated by semi-colons.

My form iterates through these orders, puts the item information into hashtables and puts each hashtable into a master hashtable. Some summary information about each order (product/order#/customer name/customer#) is displayed in my listview separated by sortable columns. Below the listview is a tab control with textboxes for the editable parts of the order details spread across three tabs.

Here is what I would like to happen:

  • User clicks on single entry: tab control textboxes fill with Order Details.
  • User edits details in tab control.
  • User clicks on another order: confirmation message checks that the change should be committed, if "Yes" then the details should be saved back to the relevant Hashtable and the display in the listview updates.
  • User selects multiple listview items: the top item should be editable in the tab control.
  • User presses "Remove Item(s)" button on a tool strip at the top of the form: the item(s) are removed from the hashtable and the listview control is updated to reflect the deletion. The textboxes are all set back to blank across the tab control.

This seems to me like pretty ordinary and reasonable behaviour. I guessed that using the SelectedIndexChanged event would offer the opportunities to do the data work. But the event fires twice on every selection/deselection and it's not always clear which items should be updated in the listview at which point.

The code for testing what kind of "selection/deselection" has just taken place and decide what action should thus be taken is starting to get quite long and I'm just wondering if I'm making things too complicated.

So:

  • Is there another event I could use to achieve my functionality goals? Or
  • Is there something about the SelectedIndexChanged event that I don't know that would help the program decide what it should be doing at any given point? Or
  • Am I just going about this the wrong way?

Any suggestions, even ones about redesigning my form would be most welcome.

EDIT: While trying to attack this problem from a different angle I am changing my master hashtable to a sortedlist. The rest of the problem remains the same.

A: 

Without knowing the code that's "starting to get quite long" I would suggest the following:

Make sure Listview1.MultiSelect is false. Use a field (or property) on your Form to track the SelectedItem. In the event, check if the new ListView1.Selecteditems[0] != this.SelectedItem

Part 2: Take a look at the DataGridView and DataTables as an alternative solution. Your data sounds quite "relational" and the Data stuff has a lot of Filtering/Sorting/Linking functionality. You could attach a List as DataSource to a Grid or go a bit further and read your data into DataTables.

Henk Holterman
Multiselect must be on I'm afraid. Sometimes we want to lose 90% of the data and having to delete 90 records individually is no fun at all. But the single datatable might be a good idea. I shall look into it.
Yup... DataTable has proven a much less headache inducing data structure. Many thanks.
A: 

Instead of updating the UI when SelectedIndexChanged is fired on the ListView, start a Timer with a short Duration (say the default 100ms), and do the UI updates in the Timer.Tick handler.

For example:

  1. Drag a ListView and Timer onto your WinForm
  2. Add a selection of Items to the ListView using the designer
  3. Add handlers for the ListView's SelectedIndexChanged event and the Timer Tick event
  4. Replace the existing code with:


private void listView1_SelectedIndexChanged(object sender, EventArgs e)
{
    timer1.Start();
}

private string GetIndices()
{
    string indices = "";
    foreach (int i in listView1.SelectedIndices)
    {
        indices += i.ToString() + ", ";
    }

    if (indices.Length > 0)
    {
        indices = indices.Substring(0, indices.Length - 2);
    }

    return indices;
}

private void timer1_Tick(object sender, EventArgs e)
{
    timer1.Stop();
    Debug.WriteLine(DateTime.Now.ToString("HH:mm:ss.fff") +
        ". Selected indices = " + GetIndices());
}


This works because the deselection and re-selection events come in very close succession to each other - quicker than the Timer's Duration. Using the Timer in this way means that the pair will be treated as a single compound event.

I hope this helps.

Dave R.
I understand why it fires twice per click. Once when it deselects the current selection and again when it selects the new one, Google searches are littered with results that explain this. At least, this is what I have been informed...
Sorry for the error in my earlier example. I've amended the original entry and hope this is more suitable.
Dave R.