6

Possible Duplicate:
Updating a Progress Bar from Another Thread

In my program, I wanted to separate non-GUI functions to another class, and leave things related to the GUI in the main class. However, I am having issues with updating a progress bar while one of the worker methods in the worker class is doing its job. I know that I will have to work with multithreading here, but I do not understand how. I may just be missing simple things, but when I look for information about it, it seems that most tutorials talk about the minutia, but do not explain the big picture very well. I partially understand what invoke and delegate commands are, but I don't really understand how they interact.

Below is stripped down version of what I want to do. How do I modify this to update the progress bar, but keep the window responsive and repainting?

Main form class:

public partial class Form1 : Form
{
    time_waster thing = new time_waster();

    public Form1()
    {
        InitializeComponent();
        progressBar1.Minimum = 0;
        progressBar1.Maximum = 100;
    }

    private void button1_Click(object sender, EventArgs e)
    {
        thing.something_that_takes_a_while();
    }
}

Separate worker class: class time_waster { public time_waster() { }

    public void something_that_takes_a_while()
    {
        int delay = 200;
        for (int i = 0; i < 100; i++)
        {
            Thread.Sleep(delay);
            //appropriate code to update the progress bar for each iteration of the for loop.
        }
    }
}
1
  • Use delegates and Invoke method to update control on UI. Commented May 23, 2012 at 21:38

3 Answers 3

8

.NET Includes a class called the BackgroundWorker, which provides methods for reporting the progress of the background thread in an event. The event is automatically called on the thread which created the BackgroundWorker (typically, the UI thread).

Subscribe to that "ProgressChanged" event, and update the progress bar in that event handler. The official MSDN Documentation provides some sample code.

Sign up to request clarification or add additional context in comments.

Comments

6
   static main()
    {
         Thread th = new Thread(calling_function);
         th.start();  
    }


    calling_function()
    {
        //do your work;
        MethodInvoker m = new MethodInvoker( ()=> progressbar.Progress=value);
        progressbar.Invoke(m);
    }

6 Comments

Okay, now to throw a wrench into the works, say that calling_function() has to be in a different class where progressbar is out of scope, how would I access it, or how would I pass back something for my GUI to read to access it?
@Xantahm You'd have to pass a reference into calling_function().
@Md: you really ought to use real C# here.
if GUI and calling_function is in different class then use class object. example GUI_class obj=new GUI_class(); obj.progressbar.invoke(m); If you need more clarification then ask it.
I have tried passing it in as a reference and it does not accept the command. Thread th = new Thread(other_class.calling_function(ref progressBar1)) does not go through, it complains about incorrect arguments (when I define callingfunction(ref ProgressBar ProgressBar1)). Other resources said to put the arguments into the th.Start() part, so I tried Thread th = new Thread(Other_function.calling function); th.Start(ref ProgressBar1). And that also does not work. Why will it not accept arguments?
|
6
MethodInvoker mi = new MethodInvoker(() => progressBar.Value= newProgressValue);
if (progressBar.InvokeRequired)
{
    progressBar.Invoke(mi);
}
else
{
    mi.Invoke();
}

This code belongs in the lengthy task. See:

  1. InvokeRequired
  2. Invoke
  3. Delegates

Lambda is just an over-fancy word for a function (or method) that is declared inline instead of as a method on class or as a raw function in languages that support them. It's "anonymous" if you don't assign it to a named variable. Be careful because they "Capture" the variables needed by them and can behave a bit strangely if you don't understand them.

The syntax for lambdas is pretty easy: () => someValue; is pretty much the same as public void SomeMethod() { return someValue; } put things into the parentheses to add parameters to the lambda. If you only have one parameter, feel free to skip the parentheses.

2 Comments

So, I am a bit confused as to how to use this. Would this be in my method that does the lengthy task, or in my main? Also, I am not sure that I fully understand what the if/else block there does. If I do understand, it is verifying whether the invoke comes from the current thread, or a different thread, is that correct? Also, I have found that the " () => proressBar.Progress... " is called a Lambda expression, and that it is "shorthand for an anonymous delegate," but what does that mean, and why do I need it there?
I am still pretty confused. if the progress bar is in my main class, and the worker thread is in another class, how would this invoke work if it was in the lengthy task? This seems like it should be in the main class, for it to still have the correct scope. Do i have to make this call some intermediary class in the main class, that in turn calls the lengthy task in my other class?

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.