AlkiZaganiaris
AlkiZaganiaris

Reputation: 13

How to correctly use BackgroundWorker to update ListView? [c# .NET 3.5]

I am trying to use a BackgroundWorker to gather some data for me and update a ListView in my form while i display a progress bar and allow for the gui to not be frozen. I am getting a cross-thread error when i try to update my ListView using the BackgroundWorker. To overcome this, i populate a temporary ListView in the BackgroundWorker and assign it to the result and then use that from the backgroundWorker1_RunWorkerCompleted to populate my original ListView.

#1: Is there a more elegant way to update/display my ListView without having to create another temporary ListView in the _RunWorkerCompleted?

#2: Is there a way to pass the original listview as an argument to the backgroundWorker?

I appreciate any feedback on this.

Thanks in advance!

Pseudo-Code

// Original ListView in Form
ListView orginalListView = new ListView();

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
    ListView backgroundList = new ListView();
    foreach(var data in database)
    {
        listViewItem = data.value;
        backgroundList.Items.Add(listViewItem);
    }
    e.Result = backgroundList;
}


private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
        // Can I avoid needing to create a temp LV ??
        ListView tempLV = new ListView();
        tempLV = (ListView)e.Result;


        foreach (ListViewItem item in tempLV.Items)
        {
            orginalListView .Items.Add((ListViewItem)item.Clone());
        }
}

Upvotes: 0

Views: 2489

Answers (2)

FAISAL
FAISAL

Reputation: 34673

To update user interface in cross-thread, you need to Invoke a new Delegate. Check this link here for information on Invoke: Invoke

Yes you can do that in an elegant way without the need of another temporary listview:

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
    foreach (var data in database)
    {
        if (orginalListView.InvokeRequired)
        {
            orginalListView.Invoke(new MethodInvoker(delegate
            {
                listViewItem = data.value;
                orginalListView.Items.Add(listViewItem);
            }));
        }
        else
        {
            listViewItem = data.value;
            orginalListView.Items.Add(listViewItem);
        }
    }
}

Upvotes: 2

st3_121
st3_121

Reputation: 32

You will likely just need to lock the resource whilst the thread is accessing it.

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
    foreach(var data in database)
    {
        listViewItem = data.value;
        String name = "orginalListView";

        lock (((ListView)this.Controls[name]))
        {
            //Update UI, invoked because on different thread.
            Invoke(new MethodInvoker(delegate { ((ListView)this.Controls[name]).Items.Add(listViewItem); }));
        }
     }
}

Upvotes: -1

Related Questions