C# Listview Subitem Text Crash

James J 586 Reputation points
2020-12-22T16:10:12.613+00:00

Problem Statement:
C# List view sub item text is getting crashed quite often when we do Delete/Insert operation on List view in Item Checked event handler[please refer event handler code in sample]. Pease find the attached sample project, WebEx clip and call stack details for the same. We tried with Lock object, Wait cursors, Listview Beginupdate() & Endupdate()functions and better handling of item checked event. But none of them helped to fix this crash.

Please suggest how to get it resolved.

Note: Form1.cs and designer file is attached for your reference.

Steps to repro the issue:

Check and Uncheck the selected list view item very frequently by using Mouse Or Keyboard

50467-callstacktext.txt50513-form1cs.txt50488-form1designercs.txt

C#
C#
An object-oriented and type-safe programming language that has its roots in the C family of languages and includes support for component-oriented programming.
10,504 questions
{count} votes

2 answers

Sort by: Most helpful
  1. Michael Taylor 50,111 Reputation points
    2020-12-22T16:51:22.89+00:00

    Your event handler looks really odd (and dangerous and slow) to me. When an item is clicked you first set the currently checked item as the selected item. This seems OK.

    Then you unhook your event handler from the UI. Why do you do this?

    Next you get the selected item. Unless you have multi-select enabled then wouldn't that be the item that is currently being checked/unchecked?

    Then you try to move the item to the top or bottom by moving items around. To do that you doing a BeginUpdate/EndUpdate call but in the middle of that you're refreshing the item at index 0 (for both the top and bottom which seems wrong). Why are you doing this? The EndUpdate should cause the UI to refresh already. You shouldn't need to do that yourself.
    As part of this you're rebuilding the subitems for all the items in the list. This seems redundant and wasteful. The UI should already handle refreshing the items and assuming you've configured the ListViewItem to have the correct subitems to begin with then moving a ListViewItem around in the list shouldn't require that you manually rebuild anything. It seems like all this code can go. I don't even think you need a LIstViewItemEx type as you could just wrap your data in a simple data wrapper but there may be more going on here then I can see.

    After the move you set the selected item again but it seems like it might be selecting the wrong index. It seems like it should either select the first or last item or, even better, not have to do anything if you just moved the items around.

    Finally it restores the event handler. Again, you shouldn't need to unhook and rehook the event handler up again.

    0 comments No comments

  2. Timon Yang-MSFT 9,576 Reputation points
    2020-12-31T09:01:35.953+00:00

    Can we consider using DataGridView instead of ListView so that we can manipulate the bound collection instead of the control itself.
    A simple code example:

            public Form1()  
            {  
                InitializeComponent();  
            }  
      
            BindingList<MyClass> list = new BindingList<MyClass>();  
            private void Form1_Load(object sender, EventArgs e)  
            {  
                list.Add(new MyClass() { ID=1,Name="test 1"});  
                list.Add(new MyClass() { ID=2,Name="test 2"});  
                list.Add(new MyClass() { ID=3,Name="test 3"});  
                list.Add(new MyClass() { ID=4,Name="test 4"});  
                list.Add(new MyClass() { ID=5,Name="test 5"});  
                dataGridView1.DataSource = list;  
            }  
            private void dataGridView1_CellContentClick(object sender, DataGridViewCellEventArgs e)  
            {  
                dataGridView1.CommitEdit(DataGridViewDataErrorContexts.Commit);  
            }  
            private void dataGridView1_CellValueChanged(object sender, DataGridViewCellEventArgs e)  
            {  
                int i = e.RowIndex;  
                MyClass myClass = list[i];  
                list.Remove(myClass);  
                list.Insert(0, myClass);  
                myClass.Checked = false;  
            }  
        }  
      
        class MyClass  
        {  
            public bool Checked { get; set; } = false;  
            public int ID { get; set; }  
            public string Name { get; set; }  
        }  
    

    If the response is helpful, please click "Accept Answer" and upvote it.
    Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.

    0 comments No comments