views:

92

answers:

3

Ok, in my app there are times when loading the DataGridView can take a minute or two. What I want to do is show a GIF in a form with no border until it reaches the end of the loading function. However, if I do:

Views.Loading ldw = new Views.Loading();
ldw.Show();
...
ldw.Close();

...it never actually draws it to the screen and I can't see it. If I do ShowDialog(), it shows the window but never gets past that line of code. I have a feeling it's because it's not a background worker or because the focus gets set back to the parent because of processing...I don't know.

My form is a blank form, added a picture box, added a gif to the picture box, and made FormBorderStyle = none. Any and all help is appreciated.

Update: Current (non-working) Code

        private void InitializeBackgroundWorker()
        {
            //Defines the DoWork Event Handler for _backgroundWorker.
            _bgWorkerReports.DoWork += new DoWorkEventHandler(bgWorkerReports_DoWork);
            //Defines the RunWorkCompleted Event Handler for _backgroundWorker.
            _bgWorkerReports.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bgWorkerReports_RunWorkerCompleted);
        }

        private void bgWorkerReports_DoWork(object sender, DoWorkEventArgs e)
        {
            ldw.Show();
            try
            {                   
                string strFilter = "";

                if (!_strSearchFilter.Equals(""))
                {
                    strFilter += strFilter.Equals("") ? " " + _strSearchFilter : "  and " + _strSearchFilter;
                }

                if (tvFigure.Nodes.Count > 0)
                {
                    if (_strFigureFilter == "ALL")
                    {
                        strFilter += " " + Constants.GetColumnName("Figure") + " LIKE '%%' ";
                    }
                    else if (!_strFigureFilter.Equals("") && !_strFigureFilter.Equals(tvFigure.TopNode.Name))
                    {
                        if (_strSearchFilter.Equals("") || !cbCurrentFigure.Checked)
                        {
                            strFilter += strFilter.Equals("") ? " " + Constants.GetColumnName("Figure") + "='" + _strFigureFilter + "'" : " and " + Constants.GetColumnName("Figure") + "='" + _strFigureFilter + "'";
                        }
                    }
                }

                if (!_strIndentureFilter.Equals(""))
                {
                    strFilter += strFilter.Equals("") ? " " + _strIndentureFilter : "  and " + _strIndentureFilter;
                }

                if (!_strReportFilter.Equals(""))
                {
                    strFilter += (!strFilter.Equals("") ? " and" : "") + " part_id in (" + _strReportFilter + ")";
                }

                if (strFilter.Length > 0)
                {
                    BindingSource bSource = new BindingSource();
                    bSource.DataSource = _dataController.PopulateDataGrid(_nViewMode, strFilter).Tables[0];

                    //Set DataSource to bindingSource for DataGridView.
                    if (_lstValidationResults.Count > 0)
                    {
                        dgvParts.DataSource = _lstValidationResults;
                        foreach (DataGridViewColumn dc in dgvParts.Columns)
                        {
                            dc.DataPropertyName = "ErrorMessage";
                            dc.Visible = true;
                            dc.SortMode = DataGridViewColumnSortMode.Programmatic;
                            dc.AutoSizeMode = DataGridViewAutoSizeColumnMode.ColumnHeader;
                        }
                        dgvParts.AutoResizeColumns();
                        return;
                    }
                    else if (!string.IsNullOrEmpty(_strFigureFilter))
                    {
                        dgvParts.DataSource = bSource;
                        dgvParts.Columns[0].Visible = false;
                        dgvParts.Columns["Description"].Resizable = DataGridViewTriState.False;
                        dgvParts.Columns["Description"].Width = 750;
                    }

                    // Automatically resize the visible rows.
                    foreach (DataGridViewColumn col in dgvParts.Columns)
                    {
                        col.SortMode = DataGridViewColumnSortMode.Automatic;
                        if (col.Name != "Description")
                        {
                            dgvParts.AutoResizeColumn(col.Index);
                        }
                    }
                    dgvParts.AutoSizeRowsMode = DataGridViewAutoSizeRowsMode.DisplayedCells;

                    // Hide the ToolTips for all the cells - redisplay if there is a report.
                    dgvParts.ShowCellToolTips = true;

                    // Set the dataGridView control's border.
                    dgvParts.BorderStyle = BorderStyle.Fixed3D;

                    // Get and set the ipb_number to the label.
                    string ipb_number = _dataController.IPBNumber;
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        private void bgWorkerReports_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            ldw.Close();
            this.Cursor = Cursors.Default; //Throws error (Cross-thread)

            FormatCells();
            BuildColumnsComboBox();

            int nTotalCount = 0;

            foreach (ListViewItem lvi in listView1.Items)
            {
                int nCount = _lstReportRecords.Where(rr => lvi.Text.Contains(rr.Description)).Count();
                nTotalCount += nCount;
                lvi.Text = (lvi.Text.Contains("(") ? lvi.Text.Substring(0, lvi.Text.IndexOf("(") + 1) : lvi.Text.Trim() + " (") + nCount.ToString() + ")";
            }

            rbAllReports.Text = (rbAllReports.Text.Contains("(") ? rbAllReports.Text.Substring(0, rbAllReports.Text.IndexOf("(") + 1) : rbAllReports.Text + " (") + nTotalCount.ToString() + ")";
            int nTaggedCount = _lstReportRecords.Where(rr => rr.Description.Contains("Tagged")).Count();
            rbTaggedRecords.Text = (rbTaggedRecords.Text.Contains("(") ? rbTaggedRecords.Text.Substring(0, rbTaggedRecords.Text.IndexOf("(") + 1) : rbTaggedRecords.Text + " (") + nTaggedCount.ToString() + ")";
        }
+5  A: 

Ideally you would have two threads: the GUI thread and the working thread (which can be a BackgroundWorker). Create and show the window in the GUI thread. Handle the loading in the BackgroundWorker's DoWork event. When the loading is done you can call Close() on the load window from the RunWorkerCompleted event and dispose of it.

LoadWindow loadWindow = new LoadWindow();
loadWindow.TopMost = true;  // make sure it doesn't get created behind other forms
loadWindow.Show();

BackgroundWorker worker = new BackgroundWorker();
worker.DoWork += new DoWorkEventHandler(worker_DoWork);
worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted);
worker.RunWorkerAsync();

void worker_DoWork(object sender, DoWorkEventArgs e)
{
    // do your loading here
}

void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    // set DataGridView datasource here
    ...

    // close loading window
    loadWindow.Close();
}

The problem you might have with displaying the window could be from the TopMost property, which must be set to true. You can also try calling BringToFront() on the loading window after you've created and showed it.

devnull
That's what I was thinking. Give me a few to implement it. Thanks.
XstreamINsanity
Ok, I'm experiencing an issue. I'm going to put my code up there as an Update. I put a break point at the beginning of the DoWork function, which I've done on another background thread I've been using, and it doesn't hit it. If you could take a look, thanks.
XstreamINsanity
Ok, the issue I have is that the stuff I'm using to determine what gets displayed in the DataGridView needs to access some of the controls, and I get a cross-thread exception for doing so. Should I make the Form with the GIF a background worker?
XstreamINsanity
And nevermind the comment about not hitting a breakpoint, I forgot to initialize my functions. :)
XstreamINsanity
Get the values from the controls in some local variables and access those from the `DoWork` event.
devnull
Can I access the controls from the RunWorkerCompleted function? Or is that still in the thread?
XstreamINsanity
Added my code so that you guys can see what I'm doing and what I need to do.
XstreamINsanity
A: 

You'll have to run the code to fill the grid on another thread. Something like:

// Set the picturebox loading state, resize the form etc.
PictureBox.SetLoadingImage();

// Initialize a new thread
Thread t = new Thread(new ThreadStart(() =>
{
    // Fill the gridview here
    GridView1.DataSource = FillWithData();
    GridView1.DataBind();

    // When finished, reset the picturebox on it's own thread
    PictureBox.Invoke((MethodInvoker)(()=> PictureBox.ClearLoadingImage() ));
}));

// Run the thread.
t.Start();
Jan Jongboom
A: 

Yes, BackgroundWorker is for exactly this type of purpose. A couple things to add:

  1. Do not interact with the UI in the worker_DoWork event as it is running on a background thread. Set e.Result when you're finished, which you can check from the RunWorkerCompleted event - or use a form-level variable.
  2. Let any exceptions fall through in the worker_DoWork event and you will see them in the worker_RunWorkerCompleted event in e.Error.
  3. If you need the ability to cancel your load, set worker.WorkerSupportsCancellation and check the e.Cancel while in your DoWork event, then you can check e.Cancelled in your RunWorkerCompleted event.
  4. You should call .Dispose() on your BackgroundWorker when finished.
ScottBai