2

In a Windows Form, I have a search box that fires an event to search a remote database and display some results. The query is pretty fast, usually just a fraction of a second, but in case the delay is noticeable there is a progress bar and label in the form's status bar. When the user clicks "Search" the status label should appear and the progress bar show some progress. Then when the result comes back the label should disappear and the progress bar should be full. Pretty basic response.

The problem is, I can't get those actions to happen in that order. Using the code below, I click "Search", nothing happens until the results are displayed, and then the progress bar fills up from 0 to 100. The label never appears. I even threw in a sleep command immediately after the event to be sure I wasn't just missing it, but it's as if the first 2 statements are not being executed. What am I doing wrong here?

 private void searchButton_Click(object sender, EventArgs e)
    {
        toolStripStatusLabel1.Visible = true;
        toolStripProgressBar1.Value = 20;
        m_changeRequestedEvents.Fire<String>("SearchTerm", searchTextBox.Text);
        toolStripProgressBar1.Value = 100;
        toolStripStatusLabel1.Visible = false;
    }
Travis Christian
  • 2,102
  • 2
  • 23
  • 36
  • Does this Fire method kick off another thread to do the database query? If not, the reason you never see the label is that you're doing everything on the same thread. In Windows Forms, the main thread is solely responsible for painting the windows and contents. If it is hung up performing ADO.NET stuff, then it can't very well get around re-painting the label. By the time it gets back to servicing controls' layout/paint events, it will have already done the query and set it back to invisible. – Sean Hanley Jun 16 '10 at 04:08
  • No, this is a single-threaded app. The event runs a DB query from another class, which then fires off another event to the UI to update a results table. I understand that it can't repaint while it's running the query, but given the above code I would think that it would partially fill the bar and display the label *before* doing the backend stuff, then execute the last 2 lines once it has finished. – Travis Christian Jun 16 '10 at 13:43
  • 2
    The UI will not update until searchButton_Click() completes. You need to run the Query on another thread. Look into BackgroundWorker. – Ray Henry Oct 08 '10 at 03:39

1 Answers1

2

The code provided changes the UI attributes, but the thread can't repaint the UI until after searchButton_Click returns. So the changes made before the event are never applied, because they're overridden by the changes made after, which are then applied when the method returns.

Instead, update the UI attributes before firing the event:

searchButton.Enabled = false;
toolStripProgressBar1.Value = 0;
toolStripStatusLabel1.Visible = true;
m_changeRequestedEvents.Fire<String>("SearchTerm", searchTextBox.Text);

and from the event handler, run the query in a separate thread (BackgroundWorker), so that the UI can update in the meantime:

private void View_OnSearchTermChangeRequest(Object sender, PropertyChangeRequestEventArgs<String> args)
{
    m_search_bgw = new BackgroundWorker();
    ...
    m_DBHandler.current_worker = m_search_bgw;
    m_search_bgw.RunWorkerAsync(args.RequestedValue);
}

then update the UI again in the method that is called when the BackgroundWorker thread completes:

void UpdateView(DataView projects)
{
    dataGridView1.DataSource = projects;
    ...
    toolStripProgressBar1.Value = 100;
    toolStripStatusLabel1.Visible = false;
}
Travis Christian
  • 2,102
  • 2
  • 23
  • 36