Search code examples
c#asynchronousiteratorlistviewitem

System.argumentoutofrangeexception while invoke Listviewitems using iterators


I have an application which must contain the items in large quantities and continuously into listviews control:

    public Form1()
    {
        InitializeComponent();
    }

    private void button1_Click(object sender, EventArgs e)
    {
        deg_loadfile load = new deg_loadfile(loadfile);
        load.BeginInvoke(new AsyncCallback(loadcallback),null);
    }

    void countfile() {

        int listcount = listView1.Items.Count;          
        for (int x = 0; x < listcount; x++) {

            listView1.BeginInvoke((MethodInvoker)delegate {
                listView1.Items[x].SubItems[1].Text = "ok";
                listView1.Items[x].SubItems[2].Text = "ok";
                listView1.Items[x].SubItems[3].Text = "done";
            },x); 

        }

    }
    void countcallback(IAsyncResult ae) {
        MessageBox.Show("count finished");

    }
    delegate void deg_count();

    void loadcallback(IAsyncResult ae) {
        MessageBox.Show("finished");

    }
    delegate void deg_loadfile();
    void loadfile() {

        string file = File.ReadAllText("hughlist.txt");
        string[] files = Regex.Split(file,"\n");

        foreach (string str in files) {
            listView1.BeginInvoke((MethodInvoker)delegate {
                ListViewItem item = new ListViewItem(str);
                item.SubItems.Add("");
                item.SubItems.Add("");
                item.SubItems.Add("");
                listView1.Items.Add(item);                
            },str);          
        } 
    }

    private void button2_Click(object sender, EventArgs e)
    {
        deg_count count = new deg_count(countfile);
        count.BeginInvoke(new AsyncCallback(countcallback),null);

    }

The code above throws system.argumentoutofrangeexception (please see image below)

link image: https://i.sstatic.net/WJ7sA.png

The iteration has exceeded the conditions that I have given, why did it happen (note:in my case, i must use "for" instead of "foreach" or other enumeration) ?

thx

UPDATE: thx to @saruman for the answer (keyword is "access to modified closure"), i've updated the code as below

for (int x = 0; x < listcount; x++) {
            var x1=x;
            listView1.BeginInvoke((MethodInvoker)delegate
            {
                listView1.Items[x1].SubItems[1].Text = "ok";
                listView1.Items[x1].SubItems[2].Text = "ok";
                listView1.Items[x1].SubItems[3].Text = "done";
            }, x1); }

Solution

  • Look up access to modified closure

    Try this

    var listcount = listView1.Items.Count;
    for (var x = 0; x < listcount; x++)
    {
       var x1 = x;
       listView1.BeginInvoke((MethodInvoker)delegate
       {
          listView1.Items[x1].SubItems[1].Text = "ok";
          listView1.Items[x1].SubItems[2].Text = "ok";
          listView1.Items[x1].SubItems[3].Text = "done";
       });
    }