0

Good day,

I'm new to whole programming thing and can't figure out / find a solution. I've been trying to populate my ListView with Items that come from another Class. But the ListView doesn't seem to do anything when the Class2 returns an Array.

Here is how i make it :

1 ) I search for something and send the value to Class2 ( Main Class in Form1 ):

private void tbSearch_KeyDown(object sender, KeyEventArgs e)
    {
        Class2 cl2 = new Class2();

        if (e.KeyCode == Keys.Enter)
        {
            if (string.IsNullOrEmpty(tbSearch.Text))
            {
                MessageBox.Show("The Textbox is Empty.....");
            }
            else
            {
               listV.Items.Clear(); 
               cl2.Search(tbSearch.Text);  // Give a value to Method in Class2
            }
        }
    }

2 ) Then in Class2 i do some internet search and return arrays with the Results :

public async void Search(string search_value)
    {
            /*** Read the XML Data that i've got from Response ****/

            foreach (XmlNode node in XMLlist)
            {
                /****** Get the values that i need and write them into an array *******/

                string[] result = new string[10];

                result[0] = series_title;
                result[1] = series_type;
                result[2] = series_episodes;
                result[3] = series_score;
                result[4] = series_id;
                result[5] = series_title_english;
                result[6] = series_status;
                result[7] = series_start_date;
                result[8] = series_end_date;
                result[9] = series_image;

                Form1 fm1 = new Form1();
                fm1.Update_SearchList(result); // Return an array to Form1
            }
    }

3) And at the end i try to populate the ListView with the returned array ( Form1 again ) :

public void Update_SearchList(string [] array)
    {
        ListViewItem item = new ListViewItem(array);
        this.listV.BeginUpdate();                
        this.listV.Items.Add(item); // Here the Item.Add() Method doesn't add new Items to the ListView or they just aren't being shown.
        this.listV.EndUpdate();          
    }

The listView.View is set to Details and the columns are being generated on Form.Load.

Is there a problem with how i execute the listView.Items.Add(); Method or is there another problem ?

When i try to do this whole operation in one single private void tbSearch_KeyDown(object sender, KeyEventArgs e) everythings works.

Thank you for your time and have a good day !

sasha_gud
  • 1,635
  • 13
  • 18
idkWhatToDo
  • 35
  • 2
  • 8

1 Answers1

0

You created a new instance of Form1 in Form1 fm1 = new Form1();, which is not the instance of your caller.

I would suggest you return the result from Search() and process in Form1, or better, a callback function.

I haven't tried but a quick bypass solution could passing Form1 as a reference to the Search() function, but TBH it looks nasty to me.

private void tbSearch_KeyDown(object sender, KeyEventArgs e) {
    //...
           cl2.Search(tbSearch.Text, ref this); // pass the ref of current instance to cl2
        }
    }
}

public async void Search(string search_value, ref Form1 frm) {
    //...
    foreach (XmlNode node in XMLlist) {
        // ...
        frm.Update_SearchList(result); // use the frm reference instead
    }
}

public void Update_SearchList(string [] array) {
    if (InvokeRequired)
        BeginInvoke(new MethodInvoker(() => Update_SearchList(array)));
    else {
        ListViewItem item = new ListViewItem(array);
        this.listV.BeginUpdate();                
        this.listV.Items.Add(item);
        this.listV.EndUpdate();  
    }        
}

Note: code not tested, just a quick idea!!!

Also, I don't think if your async will work as expected if called in a non-async function.

Edit:

You can also try to return results and proceed in main form. Find the draft code as follows, but it's synced and may block your UI thread. Again, code untested!

private void tbSearch_KeyDown(object sender, KeyEventArgs e) {
    //...
            var results = cl2.Search(tbSearch.Text);
            foreach (var item in results) Update_SearchList(item);
        }
    }
}

public List<xxx> Search(string search_value) {
    //...
    var results = new List<xxx>(); // change type to the correct type
    foreach (XmlNode node in XMLlist) {
        // ...
        results.Add(result);
    }
    return results;
}
Tide Gu
  • 815
  • 1
  • 7
  • 21
  • Thank you for looking in to this matter. I have tried to do as u have suggested. Have changed the method to sync. But i get an error that says : ` can not be passed as a ref or out argument because the element is read-only.` – idkWhatToDo Jun 01 '17 at 12:39
  • @idkWhatToDo No wonder :) It was just a quick thought. Maybe you can try my previous solution of using Events to pass variables? https://stackoverflow.com/questions/44131608/duplicate-windows-in-all-screens-with-function – Tide Gu Jun 01 '17 at 12:54
  • Your solution with Events is a bit hard to understand , but the second suggestion works. The items are being added to the List. I can live with small freezes when the function works. Now i have to figure out how to add them as i want but this is another story. Thank you for taking your time and helping me ! – idkWhatToDo Jun 01 '17 at 13:39
  • 1
    @idkWhatToDo You're most welcome! Well, if your search result is from internet, it may take unpredictable time to complete, and the freezed UI may annoy users. I would suggest you to look into `await` and `async`, and call async methods in retrieving XML data. It probably only a few lines of code or even add a few modifiers :) – Tide Gu Jun 01 '17 at 13:50