Pratik Singhal
Pratik Singhal

Reputation: 6492

How to update a listbox dynamically?

I am making a search utility and using a BackgroundWorker to search. I want that as soon as the first result is found , a new window should open up with a ListBox with the first element displayed. Now, I want that as soon as subsequent results are found, the ListBox should be updated with those results.
The method thought by me was to report the progress as soon as results are found and pass "New" and "Update" as userState to the method.
Based on the userState, I can decide whether to create a new Form or update and existing one.
Here is the code :-

    private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
    {
        if (e.UserState.ToString() == "New")
        {
            Form ResultForm = new Form();
            ResultForm.Name = "ResultForm" + i.ToString();
            LastFormName = ResultForm.Name;
            ListBox ResultListBox = new ListBox();
            ResultListBox.DataSource = SearchList;
            ResultListBox.Name = "ResultListBox" + i.ToString(); 
            LastListName = ResultListBox.Name ; 
            ResultForm.Container.Add(ResultListBox);
            ResultListBox.Show();
            ResultForm.Show();
            i++; 
        }
        else
        {
            ;
        }
    }

I have stored the names of the Last open Form and it's ListBox in the variables LastFormName and 'LastListName'. I am unable to understand what to put in the else condition, so as to update the ListBox.

Upvotes: 0

Views: 972

Answers (2)

Bradley Gatewood
Bradley Gatewood

Reputation: 248

What I would do is expose some properties on the popup form so that you can tell if it is open and have access to the list box.

    public partial class Popup : Form
    {
     public bool isOpen;
     public ListBox PopupListBox;

     public Popup()
     {
        InitializeComponent();
     }

     void Popup_FormClosing(object sender, FormClosingEventArgs e)
     {
        isOpen = false;
     }

     private void Popup_Load(object sender, EventArgs e)
     {
        this.FormClosing += Popup_FormClosing;
        PopupListBox = popupListBox;
     }
 }

Then on the calling form I would subscribe to the ProcessedChanged Event and update the listbox with the data you are passing through the ProcessedChangedEventArgs. Here is the code for the calling form

public partial class Form1 : Form
{
    Popup popupForm = new Popup();
    BackgroundWorker backgroundWorker = new BackgroundWorker();

    public Form1()
    {
        InitializeComponent();
    }

    private void Form1_Load(object sender, EventArgs e)
    {
        backgroundWorker.WorkerSupportsCancellation = true;
        backgroundWorker.WorkerReportsProgress = true;
        backgroundWorker.DoWork += backgroundWorkerDoWork;
        backgroundWorker.ProgressChanged += backgroundWorkerProgressChanged;
        backgroundWorker.RunWorkerCompleted += backgroundWorkerRunWorkerCompleted;
    }

    void backgroundWorkerRunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        if ((e.Cancelled == true))
        {
            //What do you want to do if Cancelled?
        }

        else if (!(e.Error == null))
        {
            //What do you want to do if there is an error?
        }
        else
        {
            //What do you want to do when it is done?
        }
    }

    void backgroundWorkerProgressChanged(object sender, ProgressChangedEventArgs e)
    {
        if (!popupForm.isOpen || popupForm == null)
        {
            popupForm = new Popup();
            popupForm.Show();
            popupForm.isOpen = true;
        }
        else
        {
            popupForm.Activate();
            popupForm.WindowState = FormWindowState.Normal;
        }

        popupForm.PopupListBox.Items.Add(e.ProgressPercentage.ToString() + "%");
    }

    void backgroundWorkerDoWork(object sender, DoWorkEventArgs e)
    {
        BackgroundWorker worker = sender as BackgroundWorker;

        for (int i = 1; (i <= 10); i++)
        {
            if ((worker.CancellationPending == true))
            {
                e.Cancel = true;
                break;
            }
            else
            {
                // Perform a time consuming operation and report progress.
                System.Threading.Thread.Sleep(500);
                worker.ReportProgress((i * 10));
            }
        }
    }

    private void buttonStart_Click(object sender, EventArgs e)
    {
        if (backgroundWorker.IsBusy != true)
        {
            backgroundWorker.RunWorkerAsync();
        }
    }

    private void buttonCancel_Click(object sender, EventArgs e)
    {
        if (backgroundWorker.WorkerSupportsCancellation == true)
        {
            backgroundWorker.CancelAsync();
        }
    }
}

Upvotes: 2

Harrison
Harrison

Reputation: 3963

You shouldn't be doing work in the ProgressChanged event handler

  1. You won't have access to the results as it is only passed an int for progress and user state
  2. This is on the UI thread. The entire point is to do your processing on a background thread
  3. The name DoWork event handler is clear that this is where you should do your processing.

In answer to your question. Since you create the ListBox in your event handler it goes out of scope outside the if statement. You need to create this in a more global scope. Then to add to it ResultListBox.Items.Add("ResultListBox" + i.ToString());

Upvotes: 0

Related Questions