We help IT Professionals succeed at work.

C# - Pass long acting function from child form to parent form and add bgworker and progress bar ?

gsdevEE
gsdevEE asked
on
I have a wizard application that creates/publishes data to SQL server and creates a file - it is very sloppy right now in doing so, and I would like to make it wore elegant by passing all the parameters and functiopns out of the child form where the work is currently being done to the parent form, and I would like to put the offending function in a bd worker and add a progress bar, showing text on what is going on - I have no idea how to do this, and I would think it would be pretty straightforward, but here are the questions I have (I know how to restructur the functions)

1 - How to Close a child form, but before disposing, pass the needed function info into a bg worker on the parent form,. so that the function may now be done there.

2. Tie the function into the bgworker, and add a status bar as the process runs

3.  Show what functions are being completed at what time in the progress bar dialog

I will include the code from bith forms to show what I am talking about

PARENT FORM CALLS CHILD FORM, AND ON RETURNED DIALOG RESULT PROCESSES REMAINING INFORMATION

        private void OpenApplicationWizard()
        {
 
            WizardSheet wizard = new WizardSheet(WebServiceUrl.AbsoluteUri);
           //Here is how the child form is called, perhaps just call Show ?
             DialogResult result = wizard.ShowDialog();
           //THis code gets called after child form closes
            SelectedApplicant = wizard.WelcomePage.SelectedApplicantName;

            if (result == DialogResult.Cancel) return;
            MyDataSet.Merge(wizard.wizardDataSet as DataSet, true);
            Update.UpdateSubmissionLabels(0, MyDataSet);

            _dataManager.SaveApplicationData();
            LoadNewFile("");
        }

CHILD FORM CODE THAT CLOSES WINDOW AND RETURN DIALOG RESULT
//CUSTOM EVENT THAT CLOSES FORM
   private void CompletePage_WizardFinish(object sender, WizardPageEventArgs e)
        {
            try
            {
//CODE THAT WILL BE PUT INTO BGWORKER
                UpdateApplication();
            UpdateApplicant();
                UpdateAgency();
                UpdateProcedure();
                UpdateSubmission();
                UpdateProducts();
//END
//CODE THAT RETURNS DIALOG RESULT
                ParentForm.DialogResult = DialogResult.OK;
            }
            catch (Exception ex)
            {

                StandardMessageBox.ShowMessageBox(this, ex.Message);
           
            }
        }
Comment
Watch Question

Author

Commented:
Also - if you pass a Control collection out of a child form to the parent form, are those controls values still accessible when the child form closes ?

Commented:
I would think that would be a no. If a child form is closed, all of it's controls get disposed of. I may be wrong though.
Mike TomlinsonHigh School Computer Science, Computer Applications, Digital Design, and Mathematics Teacher
Top Expert 2009

Commented:
Your child form is being shown via ShowDialog():

    DialogResult result = wizard.ShowDialog();

In "wizard" (child form), you are setting the DialogResult with:

    ParentForm.DialogResult = DialogResult.OK;

That should really be:

    this.DialogResult = DialogResult.OK;

This will cause "wizard" to automatically HIDE and code execution will return to the point where ShowDialog() was called.

At this point "wizard" is simply hidden and not disposed of.  It is now that you should grab all the information you need from it and pass it to the BackgroundWorker.

The key here is that you do NOT need to pass anything from the child to the parent.

Instead, the parent will TAKE the information from the child after the ShowDialog() call.
*Remember that code STOPPED in the parent at ShowDialog() and when DialogResult is set in the child execution returns there.

To obtain the information from the child you'll either need to:
(1) Change the controls Modifiers() property to public so they can be accessed from the parent.
< or >
(2) Create public properties in the child and set them to the desired values BEFORE setting DialogResult().

Here is a super simplified example:
    public partial class Form1 : Form
    {

        private void button1_Click(object sender, EventArgs e)
        {
            Form2 f2 = new Form2();
            if (f2.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                this.label1.Text = f2.EnteredValue;
            }
        }

    }

    public partial class Form2 : Form
    {

        private string _EnteredValue;
        public string EnteredValue
        {
            get { return this._EnteredValue; }
        }

        private void button1_Click(object sender, EventArgs e)
        {
            this._EnteredValue = textBox1.Text;
            this.DialogResult = System.Windows.Forms.DialogResult.OK;
        }

    }

Open in new window

Author

Commented:
Idle Mind your suggestion is good, as well as is Death 529  To explain my code further, I have a Form (WizardSheet), which in turn is then inherited by user control WizardPage, which is in turn then inherited by all of the controls that comprise the wizard (WelcomePage Control, CompletePage control) - would your suggestion differ with this info , or is it the same, as far as calling   this.DialogResult = DialogResult.OK;  if different can you explain the best way to do this ?

Thank you for your help, I am learning more than I did in school!
Mike TomlinsonHigh School Computer Science, Computer Applications, Digital Design, and Mathematics Teacher
Top Expert 2009

Commented:
Whatever object was displayed with ShowDialog() is the one that DialogResult() should be set against.

If your "dialog" form has UserControls within it and "ParentForm" is actually referring to the main dialog then your original could should be fine.  You would need to do some extra work to access the information contained with the usercontrols.  Again, though, the same concept can be applied by creating properties on the main form that expose the Usercontrols themselves of information within them.

From a design standpoint, it looks like you've passed in the main parent dialog into the usercontrol so you can close it from within the usercontrol.  A more "loosely coupled" approach would make the usercontrol raise a custom "CloseDialog" event that the main dialog form subscribes to.  This way the main dialog can set DialogResult itself and also gather all the information from the other usercontrols if necessary.

Author

Commented:
Ok - last question to either of you, or anyone listening for that fact...can anyone show me (in code)  how I would report the progress via text (on top of my progress bar )  what is actually happening  in the program, i.e.

//CODE THAT WILL BE PUT INTO BGWORKER
                  someLabel.Text = "Updating Applicationt";
                UpdateApplication();
                someLabel.Text = "Updating Aplicant";
                 UpdateApplicant();
                someLabel.Text ="Updating Agency";
                UpdateAgency();
                someLabel.Text = "Updating Procedure";
                UpdateProcedure();
etc....


Is this how I would do it ?
Mike TomlinsonHigh School Computer Science, Computer Applications, Digital Design, and Mathematics Teacher
Top Expert 2009

Commented:
Are going to use the actual BackgroundWorker() control?
http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.aspx

...or is this a "background" worker implemented with manual threads?

Author

Commented:
no, I was gonna use background worker control
High School Computer Science, Computer Applications, Digital Design, and Mathematics Teacher
Top Expert 2009
Commented:
To pass progress information to the main form you call the ReportProgress() method from within the DoWork() handler.  You can pass just a numeric value, which can be used to update a progressbar for example, or you can pass a numeric value AND anything as the second parameter (such as a status message).

This will cause the ProgressChanged() event fire in the main form.  Simply use "e" parameter to access the numeric and/or passed value and update your GUI from there:
http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.aspx