-3

I am new to C# and I am using windows forms

I have a problem with doing some work in BackgroundWorker.

I have 2 forms (Form1 and Form2) and 3 User Controls UC1, UC2 and UC3.

Form1 has only one button which shows Form2 which you click on it.

Form2 has 4 buttons (Btn_ShowUC1, Btn_ShowUC2, Btn_ShowUC3 and Button_Close) and 3 BackgroundWorkers.

What I am trying to do is: when I click on button1 in Form1, Form2 show up and then I want to show the relevant User control and hide the rest when I click on any button in Form2. For example: click on Btn_ShowUC1 user control1 shows up and hide the rest, click on Btn_ShowUC2 user control2 shows up and hide the rest and so on. Now showing and hiding the user controls in UI sometimes cuases Form2 to freeze therefore I used BackgroundWorkers to Show/Hide user control process.

I am using 3 BackgroundWorkers for each relavant button in case one BackgroundWorker is busy to do the show/hide processs.

In Form1:

    Form2 f2 = new Form2();

    private void button1_Click(object sender, EventArgs e)
    {
        f2.ShowDialog();
    }

In Form2:

    UserControl CurrentUserControl;
    UserControl1 uc1 = new UserControl1();
    UserControl2 uc2 = new UserControl2();
    UserControl3 uc3 = new UserControl3();

    public Form2()
    {
        InitializeComponent();
        Controls.Add(uc1);
        Controls.Add(uc2);
        Controls.Add(uc3);

    }

  private void Form2_Load(object sender, EventArgs e)
    {

        foreach (Control ctrl in this.Controls)
        {
            if (ctrl is UserControl)
            {
                ctrl.Visible = false;
            }
        }
        uc1.Visible = true;
    }


   private void Btn_ShowUC1_Click(object sender, EventArgs e)
    {
        CurrentUserControl = uc1;
        backgroundWorker1.RunWorkerAsync();

    }
    private void Btn_ShowUC2_Click(object sender, EventArgs e)
    {
        CurrentUserControl = uc2;
        backgroundWorker2.RunWorkerAsync();
    }

    private void Btn_ShowUC3_Click(object sender, EventArgs e)
    {
        CurrentUserControl = uc3;         
        backgroundWorker3.RunWorkerAsync();
    }

  private void Button_Close_Click(object sender, EventArgs e)
    {
       close();
    }

  private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
    {
        foreach (Control ctrl in this.Controls)
        {
            if (ctrl is UserControl)
            {
                ctrl.Visible = false;
            }
        }
        CurrentUserControl.Visible = true;
    }

  private void backgroundWorker2_DoWork(object sender, DoWorkEventArgs e)
    {
        foreach (Control ctrl in this.Controls)
        {
            if (ctrl is UserControl)
            {
                ctrl.Visible = false;
            }
        }
        CurrentUserControl.Visible = true;
    }

 private void backgroundWorker3_DoWork(object sender, DoWorkEventArgs e)
    {
        foreach (Control ctrl in this.Controls)
        {
            if (ctrl is UserControl)
            {
                ctrl.Visible = false;
            }
        }
        CurrentUserControl.Visible = true;
    }

When Form2 loads usercontrol1 shows up and when I click any any button the relevant user control shows up and every thing works well. However, When I close form2 and open it again and click on any button none of the user controls show up and Form2 freezes and it throws error saying "This backGroundWorker is currently busy and can not run multiple tasks concurrently" Why I am having this error? I mean I am using 3 different backGroundWorkers.

Note this is all the code I have in the project.

Anyone knows how can I fix it? I mean I want to show/hide the user controls in separate thread when I click on any button without freezing the form. I will be very happy to hear any different ideas. Thank you

Kay Lee
  • 922
  • 1
  • 12
  • 40
naouf
  • 627
  • 2
  • 18
  • 28
  • 4
    You cannot access UI controls from within your `DoWork` handler. – Uwe Keim Feb 27 '17 at 11:07
  • 5
    Aside from anything else, it looks like you background workers (all of which do the same thing, so I don't know why you have three of them) access the UI, which they shouldn't do. Basically, you can't touch the UI in a non-UI thread. – Jon Skeet Feb 27 '17 at 11:07
  • 3
    Not sure it is the cause of your problems but you should not access visual controls from a background thread, and background workers runs on background threads. So that is a no-no. You need to `.Invoke(...)` in order to run specific actions related to the visual controls on the main thread. – Lasse V. Karlsen Feb 27 '17 at 11:07
  • @Jon Skeet I used 3 backgroundworkers because when I used only one it throws same error " This backgroundworkers is busy..." – naouf Feb 27 '17 at 11:09
  • You need to [Stop BackgroundWorker on Form's Closing event](http://stackoverflow.com/questions/1731384/how-to-stop-backgroundworker-on-forms-closing-event). Aside from that, you're using `BackgroundWorker` incorrectly. – Serge Feb 27 '17 at 11:13
  • @Uwe Keim so how can I show/hide user controls without causing Form2 to freeze? any idea? because showing/hiding them in UI seems to freezes the form. keep in mind I am going to add 40 more user controls to form2 so it will be long process to show one and hide the rest. – naouf Feb 27 '17 at 11:13
  • Your solution with Bgw(s) is wrong, as already posted. The core problem: _"showing and hiding the user controls in UI sometimes cuases Form2 to freeze"_ . That shouldn't happen, there is something wrong inside those UCs. – H H Feb 27 '17 at 11:15
  • 2
    While it might be a good way to try out the BackgroundWorker, **you are using it for the wrong thing**. The UI thread, _the one you are already using by running the application in the first place_, should take care of showing/hiding controls, and any other UI related tasks. So, **this BGW is actually redundant**, just perform your for-loop inside your Button_Click event. **BGWs are made to perform long running task**, the overhead of a new thread alone makes the entire action of setting a property a waste of resources. – r41n Feb 27 '17 at 12:32
  • It is not possible to answer your question. The reason for the exception is that you are trying to re-use the same instance of `Form2`, which means you are also trying to re-use the same instances of `BackgroundWorker` that go with that instance. You shouldn't have left the BW instances running when the dialog was closed, but given that you did, you certainly can't re-use those instances. The bigger reason your question can't be answered is that you shouldn't be using BW here in the first place, but there's nothing in the code you posted to demonstrate why you did. We can't help you with that. – Peter Duniho Feb 27 '17 at 16:30

1 Answers1

1

Wrong Scenario

While it might be a good way to try out the BackgroundWorker, you are using it for the wrong thing. The UI thread, the one you are already using by running the application in the first place, should take care of showing/hiding controls, and any other UI related tasks. So, this BGW is actually redundant, just perform your for-loop inside your Button_Click event.

You are essentially changing a bit from 0 into 1 by assigning True or False to that Visibility property. The time and effort it takes for your machine to do this is non-existent. BGWs are made to perform long running task, the overhead of a new thread alone makes the entire action of setting a property a waste of resources and completely unnecessary.

Still here?

If you still want to do it this way, to learn something or whatnot, you will need to delegate this work to the UI thread. This happens because you cannot access the UI from any other thread but the UI thread. This essentially also means that your BGW becomes an even bigger waste of resources, since you essentially create a new thread to do something you want to do on the UI thread anyway. Then, from the background-thread, you tell the UI thread (from where you started) to perform the work anyway.

Community
  • 1
  • 1
r41n
  • 908
  • 7
  • 18