views:

120

answers:

4

I am trying to use a background worker in order to retrieve a large amount of data from the database without stalling the main thread. This seems to work well, except that when it comes to update the UI, the update freezes the screen. Relevant code as follows:

    private void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {               
        lvwTest.BeginUpdate();
        lvwTest.Items.Clear();

        // Populate the UI
        foreach (TestItem ti in testData)
        {
            ListViewItem lvi = lvwTest.Items.Add(ti.Value1);
            lvi.SubItems.Add(ti.Value2);
        }

        lvwTest.EndUpdate();                     
    }

The update takes around 2 - 3 seconds, for which time the screen is locked. I realise that only the main thread can update the screen, but is it possible to load this data into memory in some way (in a background thread or another instance of a listview or something) and then just display it? All I want to happen is for the program to simply refresh the data without taking up time in the main thread.

+1  A: 

If you have to load really huge amount of data into UI it will require time and it will block our app. The option is smart scrolling or pagination. You load all data but you put it piece by piece upon user request.

Andrey
+1  A: 

I recommend loading the data into memory and using a virtual mode ListView. That way, you only create the ListViewItem objects as they are needed.

Stephen Cleary
A: 

In addition to virtualization, I would recommend breaking the items into batches of, say, 100 and adding each batch in its own message. That way, the UI has a change to process other messages whilst the batches are being added to the ListView.

In other words, all the RunWorkerCompleted handler does is queue the first batch for adding in a separate message. The adding method will then add the items and then queue the next batch. This will continue until there are not more items left to add. At that point, you would re-enable the relevant portion of your UI (the ListView).

HTH,
Kent

Kent Boogaart
A: 

Since most of the above are good advice, but don't really solve your immediate problem, here is another approach: This will update your GUI and keep it responsive. Assuming you are in WinForm App?

        Application.DoEvents();
        this.Refresh();

Nevertheless, this does not mean that maybe you should not listen to the ideas from above :-)

Remy
It is a WinForm app - but back in the VB6 days, DoEvents was frowned upon because it could change the sequence of events. Is that not the case in C#?
pm_2
You might be right, it's still a bit of a hack from what I've heard. Depends on the complexity of your App. I've rewritten my last simple app to WPF, that is actually a really nice Framework.
Remy