Click here to Skip to main content
15,886,199 members
Please Sign up or sign in to vote.
4.00/5 (1 vote)
See more:
Hello,
on my form there is a button starting several jobs.
The methods behind are:
1. gathering Files
2. copying
3. next Method WAITING for copying to be finished.

Copying-Method is called asynchronously (because of ProgressBar and "freezing" form.
I got copying running, where and how should I FORCE copying wait, till copying is finished? Next-method (3) shouldn't be started before. I experimented with EndInvoke, IAsyncResult etc. but I only got confused and next-Method doesn't wait for copying...
The code:
delegate void ShowProgressDelegate(string target, int totalDigits, int digitsSoFar);
delegate void CalcDelegate(int digits);
void ShowProgress(string target, int totalDigits, int digitsSoFar)
        {
            //
            if (lblProgressBar.InvokeRequired == false)
            {
                lblProgressBar.Text = target;
                pBar1.Maximum = totalDigits;
                pBar1.Value = digitsSoFar;
            }
            else //
            {
                ShowProgressDelegate showProgress = new ShowProgressDelegate(ShowProgress);
                //Invoke..
                IAsyncResult ar = BeginInvoke(showProgress, new object[] {target,totalDigits,digitsSoFar });
                EndInvoke(ar);
            }

        }

//Button-Routine...
private void CopyWithProgressBar(ArrayList myAl)
        {
            //ProgressBar einblenden..
            this.pBar1.Visible = true;
            CalcDelegate calcDel = new CalcDelegate(DoJob);
            calcDel.BeginInvoke((int)myAl.Count, null, null);
           
        }

        private void DoJob(int digits)
        {
            Object[] jajco = myAl.ToArray();
            //ShowProgress
            ShowProgress("Kopieren: ", digits, 0);
            if(digits>0)
            {
                for (int x = 0; x < digits; x++)
                {
                    string input = jajco[x].ToString().Substring(0, jajco[x].ToString().IndexOf(","));
                    string target = jajco[x].ToString().Substring(jajco[x].ToString().IndexOf(",") + 1);
                    File.Copy(input, target, true);
                    //Show Progress..
                    ShowProgress("Kopieren: " + target, digits, x);
                }

            }
        }

Thank you for any help
Posted
Updated 24-May-11 1:59am
v2

With asynchronous delegate invocation the most useful way to detect completion is to use a callback. This is a basic template which you can adapt:

using System.Runtime.Remoting.Messaging;

private delegate void ProcessingMethodDelegate();

public void StartAsync() {
  ProcessingMethodDelegate pm = new ProcessingMethodDelegate(ProcessingMethod);
  pm.BeginInvoke(AsyncComplete, null);
}

public void ProcessingMethod () {
   // do stuff
}

/// <summary>
/// Completion method called on a Threadpool thread
/// </summary>
public void AsyncComplete(IAsyncResult ar) {
  AsyncResult result = (AsyncResult)ar;
  try {
    ((ProcessingMethodDelegate)result.AsyncDelegate).EndInvoke(ar);
  } catch (Exception e) {
    // handle exception raised by ProcessingMethod
  } finally {
    // next actions
  }
}


In your case, unless you really have a great desire to use asynchronous delegates, I would suggest the Backgroundworker class[^] which has progress and completion events, both of which are raised on the UI thread.

Whatever you choose the next action is initiated from the completion handler and in a UI application this is often nothing more than enabling buttons that were disabled for the duration of the background task.

In response to your comment:
With a sequence of tasks one must end before the next is allowed to start and your code has to enforce this requirement.

A possible solution is to run the sequence in one thread, i.e. run the whole sequence as one background operation.

e.g.
C#
public void ProcessingMethod () {
  Task1();
  Task2();
  Task3();
}

The alternative is my original suggestion which is to chain the completion handlers of each individual asynchronous task so that completion of one starts the next.

Whether you use Backgroundworker or asynchronous delegates makes no difference to the logical flow of the program, it is just that making it happen correctly is more work for the programmer.


Alan.
 
Share this answer
 
v2
Comments
andywawa 24-May-11 9:51am    
Hi Alan,
thanks for your answer. I've already tried to solve my problem using BackgroundWorker, but it will not work with the completion event.
Unfortunately your solution doesn't work either. I suppose I place the next action (in my case the method no. 3 under the button after copying) in "finally" block. There is also a method 4 as well and the program tries to start with the method 4 immidiately and crashes, for copying must be finished befor the method 4 can start...
Regards
Alan N 24-May-11 10:42am    
See updated answer
Sergey Alexandrovich Kryukov 24-May-11 15:59pm    
Correct, my 5.
--SA
Sergey Alexandrovich Kryukov 24-May-11 16:08pm    
I added links to my past answers explaining the mechanism and my invocation code, please see.
--SA
andywawa 25-May-11 5:27am    
Hello SA, hello Alan,
thanks for your answers. Hmm, it's pretty complicated. After reviewing all your links, documentations etc. the picture is still not much as clear as I hoped. I wish I could have from you (if it were possible) a following manual:
1. design decision: a form, a button, some methods on it should run in "classical" top-down manner, but NOT as a single thread (form freezes...) and wating for each other to be complited.
2. what to use: background worker or ansynchronous method (pros and cons?)
3. simple working example
4. that would be (from my point of view) a perfect manual. For a beginner it's hard enough. :-)
Regards
In addition to the solution by Alan.

Invoke is not a call at all. It is used to collect all data needed to the call (delegate instance plus parameters) and queue it to the UI thread where the call is actually done. It can only be done with UI.

Also, these invocation methods are not only of the System.Windows.Forms.Conrol but also of System.Threading.Dispatcher, which can works with both Forms and WPF.

Please see how it works in my past answers:
Control.Invoke() vs. Control.BeginInvoke()[^],
Problem with Treeview Scanner And MD5[^].

Basically, it works only on UI threads (some mistakenly thinks it works for all thread because the Dispatcher can invoke anywhere, but in fact it is reduced to a simple call on a current thread!).

A special effort is needed to create such mechanism for other threads. I've done it, see full code and usage samples in my short Tips/Trick article here:
Simple Blocking Queue for Thread Communication and Inter-thread Invocation[^].

—SA
 
Share this answer
 
Comments
Espen Harlinn 24-May-11 19:36pm    
Good points, my 5
Sergey Alexandrovich Kryukov 24-May-11 20:52pm    
Thank you, Espen.
--SA

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900