Delegates and threads

  • Thread starter Thread starter Grant
  • Start date Start date
G

Grant

I am having great difficulty understanding this and any code samples I find
online are kilometres long and complicated to understand...Please could
someone give me a simple exampe of how to get a delegate passed to my worked
class so that my main form can update its progress bar? I know it has
something to do with begininvoke and endinvoke etc, but I just need a simple
sample to understand the convention.


Code from my main form:
-----------------------------------
form1Delegate dlgate = new form1Delegate(IncreaseProgressBar);
//thing.countUpToaMillionOrSomething(new
form1Delegate(this.IncreaseProgressBar));
Thread thread = new Thread(new
ThreadStart(thing.countUpToaMillionOrSomething(dlgate)));
thread.Start();
-----------------------------------

Code from my worker class called 'thing'
-----------------------------------
public static void countUpToaMillionOrSomething(Form1.form1Delegate
myMethodDelegate)
{
int x = 0;
while ( x < 50)
{
Thread.Sleep(70);
x ++ ;
myMethodDelegate();
}
}
-----------------------------------


I can only get it to work synchronously with the following line:

thing.countUpToaMillionOrSomething(new
form1Delegate(this.IncreaseProgressBar));

If I try compile with the thread example above it spews about 'Method name
expected' and underlines the following bit of code:

thing.countUpToaMillionOrSomething(dlgate)

Any help greatly appreciated,
Thanks,
Grant
 
You don't need to use the Thread class to invoke the delegate asynchronously, however, invoking it using BeginInvoke will execute
the method that the delegate points to on a ThreadPool thread. Also, ProgressBar (and any other WinForms control) requires most of
its members to be executed/accessed on the thread that the control was created on. To account for this requirement, a proper
example can't be too simple.

Here's the simplest approach to updating a progress bar aynchronously in a WinForms app (the proper way). I'm assuming that each
method is contained by a class derived from System.Windows.Forms.Form:

private delegate void UpdateProgressInvoker(int Position);
private System.Windows.Forms.ProgressBar progressBar;

/// <summary>Test the progress bar asynchronous update code</summary>
public void DoSomeWork()
{
progressBar.Minimum = 0;
progressBar.Maximum = 100;

for (int i = 0; i < 10000; i++)
{
// Create a pointer to the UpdateProgress method
UpdateProgressInvoker del = new UpdateProgressInvoker(UpdateProgress);

// Invoke the method asynchronously
del.BeginInvoke((int) (i / 100), null, null);

// Tell the app to handle pending messages
// (so the form doesn't freeze and the progress bar is updated visually)
Application.DoEvents();
}
}


/// <summary>
/// This method does not update the progress bar directly. Instead, it ensures that the
/// <see cref="UpdateProgressCore" /> method (which actually does the work) is executed on the
/// thread that the ProgressBar was created on.
/// </summary>
private void UpdateProgress(int Position)
{
// Check if the Form.InvokeRequired property is true. This will indicate that
// the currently executing thread is not the thread that the ProgressBar was created on.
// To update the progress bar synchronously, we will need to invoke the method on the
// main thread.
// [this] must be a reference to a Form object.
if (!this.InvokeRequired)
{
// Create a pointer to the UpdateProgressCore method which performs the actual update
UpdateProgressInvoker del = new UpdateProgressInvoker(UpdateProgressCore);

// Invoke the method asynchronously on the main thread of the application.
// By using Form.Invoke, we ensure that our progress bar will be updated properly.
this.Invoke(del, new object[] { Position });
}
else
// Currently executing thread is the ProgressBar's thread,
// so update the progress bar normally
UpdateProgressCore(Position);
}

/// <summary>
/// Do not call this method directly. Instead, call <see cref="UpdateProgress" />.
/// </summary>
private void UpdateProgressCore(int Position)
{
progressBar.Value = Position;
}
 
That looks great - apart from I don't understand why you call DoEvents - how does this help?

Regards

Richard Blewett - DevelopMentor
http://www.dotnetconsult.co.uk/weblog


nntp://news.microsoft.com/microsoft.public.dotnet.languages.csharp/<#[email protected]>

You don't need to use the Thread class to invoke the delegate asynchronously, however, invoking it using BeginInvoke will execute
the method that the delegate points to on a ThreadPool thread. Also, ProgressBar (and any other WinForms control) requires most of
its members to be executed/accessed on the thread that the control was created on. To account for this requirement, a proper
example can't be too simple.

Here's the simplest approach to updating a progress bar aynchronously in a WinForms app (the proper way). I'm assuming that each
method is contained by a class derived from System.Windows.Forms.Form:

private delegate void UpdateProgressInvoker(int Position);
private System.Windows.Forms.ProgressBar progressBar;

/// <summary>Test the progress bar asynchronous update code</summary>
public void DoSomeWork()
{
progressBar.Minimum = 0;
progressBar.Maximum = 100;

for (int i = 0; i < 10000; i++)
{
// Create a pointer to the UpdateProgress method
UpdateProgressInvoker del = new UpdateProgressInvoker(UpdateProgress);

// Invoke the method asynchronously
del.BeginInvoke((int) (i / 100), null, null);

// Tell the app to handle pending messages
// (so the form doesn't freeze and the progress bar is updated visually)
Application.DoEvents();
}
}


/// <summary>
/// This method does not update the progress bar directly. Instead, it ensures that the
/// <see cref="UpdateProgressCore" /> method (which actually does the work) is executed on the
/// thread that the ProgressBar was created on.
/// </summary>
private void UpdateProgress(int Position)
{
// Check if the Form.InvokeRequired property is true. This will indicate that
// the currently executing thread is not the thread that the ProgressBar was created on.
// To update the progress bar synchronously, we will need to invoke the method on the
// main thread.
// [this] must be a reference to a Form object.
if (!this.InvokeRequired)
{
// Create a pointer to the UpdateProgressCore method which performs the actual update
UpdateProgressInvoker del = new UpdateProgressInvoker(UpdateProgressCore);

// Invoke the method asynchronously on the main thread of the application.
// By using Form.Invoke, we ensure that our progress bar will be updated properly.
this.Invoke(del, new object[] { Position });
}
else
// Currently executing thread is the ProgressBar's thread,
// so update the progress bar normally
UpdateProgressCore(Position);
}

/// <summary>
/// Do not call this method directly. Instead, call <see cref="UpdateProgress" />.
/// </summary>
private void UpdateProgressCore(int Position)
{
progressBar.Value = Position;
}


--
Dave Sexton
[email protected]
-----------------------------------------------------------------------
Grant said:
I am having great difficulty understanding this and any code samples I find online are kilometres long and complicated to
understand...Please could someone give me a simple exampe of how to get a delegate passed to my worked class so that my main form
can update its progress bar? I know it has something to do with begininvoke and endinvoke etc, but I just need a simple sample to
understand the convention.


Code from my main form:
-----------------------------------
form1Delegate dlgate = new form1Delegate(IncreaseProgressBar);
//thing.countUpToaMillionOrSomething(new form1Delegate(this.IncreaseProgressBar));
Thread thread = new Thread(new ThreadStart(thing.countUpToaMillionOrSomething(dlgate)));
thread.Start();
-----------------------------------

Code from my worker class called 'thing'
-----------------------------------
public static void countUpToaMillionOrSomething(Form1.form1Delegate myMethodDelegate)
{
int x = 0;
while ( x < 50)
{
Thread.Sleep(70);
x ++ ;
myMethodDelegate();
}
}
-----------------------------------


I can only get it to work synchronously with the following line:

thing.countUpToaMillionOrSomething(new form1Delegate(this.IncreaseProgressBar));

If I try compile with the thread example above it spews about 'Method name expected' and underlines the following bit of code:

thing.countUpToaMillionOrSomething(dlgate)

Any help greatly appreciated,
Thanks,
Grant



[microsoft.public.dotnet.languages.csharp]
 
Comment out Application.DoEvents and you'll see how it helps.

Has to do with the fact that Windows uses a "Message Loop" so method invocations for WinForms controls aren't exactly "real-time".
The message loop is like a queue, meaning first-in first-out. Your whole windows app depends on the messages from the queue
reaching the main window procedure in order to process events, such as System.Windows.Forms.Form.Paint event. Without this message,
the form will never refresh, and neither will it's child controls (i.e. progress bar). User actions are also messages, so the
window would "freeze" up, not allowing you to interact with it, while the "DoSomeWork" method is executing on the main window
thread.

In other words:
1. Application.Run starts a message loop
2. Your Form (main application window) processes messages on the loop
3. My method (DoSomeWork) blocks the thread, not allowing it to accept messages while it is running
4. Application.DoEvents allows the Form to process messages currently in the queue, effectively updating the Form while
DoSomeWork is doing some work :)



--
Dave Sexton
[email protected]
-----------------------------------------------------------------------
Richard Blewett said:
That looks great - apart from I don't understand why you call DoEvents - how does this help?

Regards

Richard Blewett - DevelopMentor
http://www.dotnetconsult.co.uk/weblog


nntp://news.microsoft.com/microsoft.public.dotnet.languages.csharp/<#[email protected]>

You don't need to use the Thread class to invoke the delegate asynchronously, however, invoking it using BeginInvoke will execute
the method that the delegate points to on a ThreadPool thread. Also, ProgressBar (and any other WinForms control) requires most of
its members to be executed/accessed on the thread that the control was created on. To account for this requirement, a proper
example can't be too simple.

Here's the simplest approach to updating a progress bar aynchronously in a WinForms app (the proper way). I'm assuming that each
method is contained by a class derived from System.Windows.Forms.Form:

private delegate void UpdateProgressInvoker(int Position);
private System.Windows.Forms.ProgressBar progressBar;

/// <summary>Test the progress bar asynchronous update code</summary>
public void DoSomeWork()
{
progressBar.Minimum = 0;
progressBar.Maximum = 100;

for (int i = 0; i < 10000; i++)
{
// Create a pointer to the UpdateProgress method
UpdateProgressInvoker del = new UpdateProgressInvoker(UpdateProgress);

// Invoke the method asynchronously
del.BeginInvoke((int) (i / 100), null, null);

// Tell the app to handle pending messages
// (so the form doesn't freeze and the progress bar is updated visually)
Application.DoEvents();
}
}


/// <summary>
/// This method does not update the progress bar directly. Instead, it ensures that the
/// <see cref="UpdateProgressCore" /> method (which actually does the work) is executed on the
/// thread that the ProgressBar was created on.
/// </summary>
private void UpdateProgress(int Position)
{
// Check if the Form.InvokeRequired property is true. This will indicate that
// the currently executing thread is not the thread that the ProgressBar was created on.
// To update the progress bar synchronously, we will need to invoke the method on the
// main thread.
// [this] must be a reference to a Form object.
if (!this.InvokeRequired)
{
// Create a pointer to the UpdateProgressCore method which performs the actual update
UpdateProgressInvoker del = new UpdateProgressInvoker(UpdateProgressCore);

// Invoke the method asynchronously on the main thread of the application.
// By using Form.Invoke, we ensure that our progress bar will be updated properly.
this.Invoke(del, new object[] { Position });
}
else
// Currently executing thread is the ProgressBar's thread,
// so update the progress bar normally
UpdateProgressCore(Position);
}

/// <summary>
/// Do not call this method directly. Instead, call <see cref="UpdateProgress" />.
/// </summary>
private void UpdateProgressCore(int Position)
{
progressBar.Value = Position;
}


--
Dave Sexton
[email protected]
-----------------------------------------------------------------------
Grant said:
I am having great difficulty understanding this and any code samples I find online are kilometres long and complicated to
understand...Please could someone give me a simple exampe of how to get a delegate passed to my worked class so that my main form
can update its progress bar? I know it has something to do with begininvoke and endinvoke etc, but I just need a simple sample to
understand the convention.


Code from my main form:
-----------------------------------
form1Delegate dlgate = new form1Delegate(IncreaseProgressBar);
//thing.countUpToaMillionOrSomething(new form1Delegate(this.IncreaseProgressBar));
Thread thread = new Thread(new ThreadStart(thing.countUpToaMillionOrSomething(dlgate)));
thread.Start();
-----------------------------------

Code from my worker class called 'thing'
-----------------------------------
public static void countUpToaMillionOrSomething(Form1.form1Delegate myMethodDelegate)
{
int x = 0;
while ( x < 50)
{
Thread.Sleep(70);
x ++ ;
myMethodDelegate();
}
}
-----------------------------------


I can only get it to work synchronously with the following line:

thing.countUpToaMillionOrSomething(new form1Delegate(this.IncreaseProgressBar));

If I try compile with the thread example above it spews about 'Method name expected' and underlines the following bit of code:

thing.countUpToaMillionOrSomething(dlgate)

Any help greatly appreciated,
Thanks,
Grant



[microsoft.public.dotnet.languages.csharp]
 
Yes, I understand the internals of the windows messaging based windows subsystem. What was eluding me was the logic of the method. I had misread and thought you were calling DoSomeWork on a threadpool thread. In which case the Application.DoEvents succeeds but doesn't do what you expected.

In any case your example shows something that seems bizarrre rather than what you would do. The UI thread is asking the worker thread to process a call which is marshalled back to the UI thread - its far simpler for the UI thread to update the progress bar directly and more effiecient.

You example would be much more real world if the worker thread was performing the work and then passing the requests to update the progress bar back to the UI thread via control.Invoke (or BeginInvoke which is preferable in my book)

Regards

Richard Blewett - DevelopMentor
http://www.dotnetconsult.co.uk/weblog
http://www.dotnetconsult.co.uk

Comment out Application.DoEvents and you'll see how it helps.

Has to do with the fact that Windows uses a "Message Loop" so method invocations for WinForms controls aren't exactly "real-time".
The message loop is like a queue, meaning first-in first-out. Your whole windows app depends on the messages from the queue
reaching the main window procedure in order to process events, such as System.Windows.Forms.Form.Paint event. Without this message,
the form will never refresh, and neither will it's child controls (i.e. progress bar). User actions are also messages, so the
window would "freeze" up, not allowing you to interact with it, while the "DoSomeWork" method is executing on the main window
thread.

In other words:
1. Application.Run starts a message loop
2. Your Form (main application window) processes messages on the loop
3. My method (DoSomeWork) blocks the thread, not allowing it to accept messages while it is running
4. Application.DoEvents allows the Form to process messages currently in the queue, effectively updating the Form while
DoSomeWork is doing some work :)
 
Is there something particular you are trying to prove here?
You run 'DoSomeWork' on the main UI thread, in 'DoSomeWork' you call an
asynchronous delegate to run 'UpdateProgress', as this one runs on a thread
from the pool you have to marshal the call to 'UpdateProgressCore' (using
the synchronous Invoke) so it runs on the UI thread.
So basically, you are running a long task on the UI thread , call a delegate
to update the UI on another thread and then need to Invoke to marshal the
call to the UI is plain silly. No surprise you need to call DoEvents.
Agreed, if you do not call DoEvents you'll consume all available pool
threads and crash (Invoke doesn't return as the messages don't get
dispatched) , but you shouldn't run the task on the UI thread in the first
place.


Willy.




Dave said:
Comment out Application.DoEvents and you'll see how it helps.

Has to do with the fact that Windows uses a "Message Loop" so method
invocations for WinForms controls aren't exactly "real-time". The message
loop is like a queue, meaning first-in first-out. Your whole windows app
depends on the messages from the queue reaching the main window procedure
in order to process events, such as System.Windows.Forms.Form.Paint event.
Without this message, the form will never refresh, and neither will it's
child controls (i.e. progress bar). User actions are also messages, so
the window would "freeze" up, not allowing you to interact with it, while
the "DoSomeWork" method is executing on the main window thread.

In other words:
1. Application.Run starts a message loop
2. Your Form (main application window) processes messages on the loop
3. My method (DoSomeWork) blocks the thread, not allowing it to accept
messages while it is running
4. Application.DoEvents allows the Form to process messages currently
in the queue, effectively updating the Form while DoSomeWork is doing some
work :)



--
Dave Sexton
[email protected]
-----------------------------------------------------------------------
Richard Blewett said:
That looks great - apart from I don't understand why you call DoEvents -
how does this help?

Regards

Richard Blewett - DevelopMentor
http://www.dotnetconsult.co.uk/weblog



nntp://news.microsoft.com/microsoft.public.dotnet.languages.csharp/<#[email protected]>

You don't need to use the Thread class to invoke the delegate
asynchronously, however, invoking it using BeginInvoke will execute
the method that the delegate points to on a ThreadPool thread. Also,
ProgressBar (and any other WinForms control) requires most of
its members to be executed/accessed on the thread that the control was
created on. To account for this requirement, a proper
example can't be too simple.

Here's the simplest approach to updating a progress bar aynchronously in
a WinForms app (the proper way). I'm assuming that each
method is contained by a class derived from System.Windows.Forms.Form:

private delegate void UpdateProgressInvoker(int Position);
private System.Windows.Forms.ProgressBar progressBar;

/// <summary>Test the progress bar asynchronous update code</summary>
public void DoSomeWork()
{
progressBar.Minimum = 0;
progressBar.Maximum = 100;

for (int i = 0; i < 10000; i++)
{
// Create a pointer to the UpdateProgress method
UpdateProgressInvoker del = new UpdateProgressInvoker(UpdateProgress);

// Invoke the method asynchronously
del.BeginInvoke((int) (i / 100), null, null);

// Tell the app to handle pending messages
// (so the form doesn't freeze and the progress bar is updated visually)
Application.DoEvents();
}
}


/// <summary>
/// This method does not update the progress bar directly. Instead, it
ensures that the
/// <see cref="UpdateProgressCore" /> method (which actually does the
work) is executed on the
/// thread that the ProgressBar was created on.
/// </summary>
private void UpdateProgress(int Position)
{
// Check if the Form.InvokeRequired property is true. This will indicate
that
// the currently executing thread is not the thread that the ProgressBar
was created on.
// To update the progress bar synchronously, we will need to invoke the
method on the
// main thread.
// [this] must be a reference to a Form object.
if (!this.InvokeRequired)
{
// Create a pointer to the UpdateProgressCore method which performs the
actual update
UpdateProgressInvoker del = new
UpdateProgressInvoker(UpdateProgressCore);

// Invoke the method asynchronously on the main thread of the
application.
// By using Form.Invoke, we ensure that our progress bar will be updated
properly.
this.Invoke(del, new object[] { Position });
}
else
// Currently executing thread is the ProgressBar's thread,
// so update the progress bar normally
UpdateProgressCore(Position);
}

/// <summary>
/// Do not call this method directly. Instead, call <see
cref="UpdateProgress" />.
/// </summary>
private void UpdateProgressCore(int Position)
{
progressBar.Value = Position;
}


--
Dave Sexton
[email protected]
-----------------------------------------------------------------------
Grant said:
I am having great difficulty understanding this and any code samples I
find online are kilometres long and complicated to
understand...Please could someone give me a simple exampe of how to get
a delegate passed to my worked class so that my main form
can update its progress bar? I know it has something to do with
begininvoke and endinvoke etc, but I just need a simple sample to
understand the convention.


Code from my main form:
-----------------------------------
form1Delegate dlgate = new form1Delegate(IncreaseProgressBar);
//thing.countUpToaMillionOrSomething(new
form1Delegate(this.IncreaseProgressBar));
Thread thread = new Thread(new
ThreadStart(thing.countUpToaMillionOrSomething(dlgate)));
thread.Start();
-----------------------------------

Code from my worker class called 'thing'
-----------------------------------
public static void countUpToaMillionOrSomething(Form1.form1Delegate
myMethodDelegate)
{
int x = 0;
while ( x < 50)
{
Thread.Sleep(70);
x ++ ;
myMethodDelegate();
}
}
-----------------------------------


I can only get it to work synchronously with the following line:

thing.countUpToaMillionOrSomething(new
form1Delegate(this.IncreaseProgressBar));

If I try compile with the thread example above it spews about 'Method
name expected' and underlines the following bit of code:

thing.countUpToaMillionOrSomething(dlgate)

Any help greatly appreciated,
Thanks,
Grant



[microsoft.public.dotnet.languages.csharp]
 
Lol. Thanks for the feedback, but does anyone read the initial question anymore??
Please could someone give me a simple exampe of how to get a delegate passed to my worked class so that my main form can update
its progress bar?

That's what he wanted. He needed to understand delegates, I assumed.

Anyway... I think you missed the part where i check Form.RequiresInvoke, and if it is false, do the update directly.
UpdateProgessCore is exactly what is sounds like... a method to update a progress bar. How do I know he's able to do this in one
line of code? That's why it's a seperate method.

Encapsulation.

--
Dave Sexton
[email protected]
-----------------------------------------------------------------------
Willy Denoyette said:
Is there something particular you are trying to prove here?
You run 'DoSomeWork' on the main UI thread, in 'DoSomeWork' you call an asynchronous delegate to run 'UpdateProgress', as this one
runs on a thread from the pool you have to marshal the call to 'UpdateProgressCore' (using the synchronous Invoke) so it runs on
the UI thread.
So basically, you are running a long task on the UI thread , call a delegate to update the UI on another thread and then need to
Invoke to marshal the call to the UI is plain silly. No surprise you need to call DoEvents.
Agreed, if you do not call DoEvents you'll consume all available pool threads and crash (Invoke doesn't return as the messages
don't get dispatched) , but you shouldn't run the task on the UI thread in the first place.


Willy.




Dave said:
Comment out Application.DoEvents and you'll see how it helps.

Has to do with the fact that Windows uses a "Message Loop" so method invocations for WinForms controls aren't exactly
"real-time". The message loop is like a queue, meaning first-in first-out. Your whole windows app depends on the messages from
the queue reaching the main window procedure in order to process events, such as System.Windows.Forms.Form.Paint event. Without
this message, the form will never refresh, and neither will it's child controls (i.e. progress bar). User actions are also
messages, so the window would "freeze" up, not allowing you to interact with it, while the "DoSomeWork" method is executing on
the main window thread.

In other words:
1. Application.Run starts a message loop
2. Your Form (main application window) processes messages on the loop
3. My method (DoSomeWork) blocks the thread, not allowing it to accept messages while it is running
4. Application.DoEvents allows the Form to process messages currently in the queue, effectively updating the Form while
DoSomeWork is doing some work :)



--
Dave Sexton
[email protected]
-----------------------------------------------------------------------
Richard Blewett said:
That looks great - apart from I don't understand why you call DoEvents - how does this help?

Regards

Richard Blewett - DevelopMentor
http://www.dotnetconsult.co.uk/weblog



nntp://news.microsoft.com/microsoft.public.dotnet.languages.csharp/<#[email protected]>

You don't need to use the Thread class to invoke the delegate asynchronously, however, invoking it using BeginInvoke will
execute
the method that the delegate points to on a ThreadPool thread. Also, ProgressBar (and any other WinForms control) requires most
of
its members to be executed/accessed on the thread that the control was created on. To account for this requirement, a proper
example can't be too simple.

Here's the simplest approach to updating a progress bar aynchronously in a WinForms app (the proper way). I'm assuming that each
method is contained by a class derived from System.Windows.Forms.Form:

private delegate void UpdateProgressInvoker(int Position);
private System.Windows.Forms.ProgressBar progressBar;

/// <summary>Test the progress bar asynchronous update code</summary>
public void DoSomeWork()
{
progressBar.Minimum = 0;
progressBar.Maximum = 100;

for (int i = 0; i < 10000; i++)
{
// Create a pointer to the UpdateProgress method
UpdateProgressInvoker del = new UpdateProgressInvoker(UpdateProgress);

// Invoke the method asynchronously
del.BeginInvoke((int) (i / 100), null, null);

// Tell the app to handle pending messages
// (so the form doesn't freeze and the progress bar is updated visually)
Application.DoEvents();
}
}


/// <summary>
/// This method does not update the progress bar directly. Instead, it ensures that the
/// <see cref="UpdateProgressCore" /> method (which actually does the work) is executed on the
/// thread that the ProgressBar was created on.
/// </summary>
private void UpdateProgress(int Position)
{
// Check if the Form.InvokeRequired property is true. This will indicate that
// the currently executing thread is not the thread that the ProgressBar was created on.
// To update the progress bar synchronously, we will need to invoke the method on the
// main thread.
// [this] must be a reference to a Form object.
if (!this.InvokeRequired)
{
// Create a pointer to the UpdateProgressCore method which performs the actual update
UpdateProgressInvoker del = new UpdateProgressInvoker(UpdateProgressCore);

// Invoke the method asynchronously on the main thread of the application.
// By using Form.Invoke, we ensure that our progress bar will be updated properly.
this.Invoke(del, new object[] { Position });
}
else
// Currently executing thread is the ProgressBar's thread,
// so update the progress bar normally
UpdateProgressCore(Position);
}

/// <summary>
/// Do not call this method directly. Instead, call <see cref="UpdateProgress" />.
/// </summary>
private void UpdateProgressCore(int Position)
{
progressBar.Value = Position;
}


--
Dave Sexton
[email protected]
-----------------------------------------------------------------------
I am having great difficulty understanding this and any code samples I find online are kilometres long and complicated to
understand...Please could someone give me a simple exampe of how to get a delegate passed to my worked class so that my main
form
can update its progress bar? I know it has something to do with begininvoke and endinvoke etc, but I just need a simple sample
to
understand the convention.


Code from my main form:
-----------------------------------
form1Delegate dlgate = new form1Delegate(IncreaseProgressBar);
//thing.countUpToaMillionOrSomething(new form1Delegate(this.IncreaseProgressBar));
Thread thread = new Thread(new ThreadStart(thing.countUpToaMillionOrSomething(dlgate)));
thread.Start();
-----------------------------------

Code from my worker class called 'thing'
-----------------------------------
public static void countUpToaMillionOrSomething(Form1.form1Delegate myMethodDelegate)
{
int x = 0;
while ( x < 50)
{
Thread.Sleep(70);
x ++ ;
myMethodDelegate();
}
}
-----------------------------------


I can only get it to work synchronously with the following line:

thing.countUpToaMillionOrSomething(new form1Delegate(this.IncreaseProgressBar));

If I try compile with the thread example above it spews about 'Method name expected' and underlines the following bit of code:

thing.countUpToaMillionOrSomething(dlgate)

Any help greatly appreciated,
Thanks,
Grant





[microsoft.public.dotnet.languages.csharp]
 
Inline

Willy.

Dave said:
Lol. Thanks for the feedback, but does anyone read the initial question
anymore??

Sure I do, but as OP started with: "I am having great difficulty
understanding this and any code samples I find .." ... does ring a bell for
me. Clearly OP doesn't understand delegates, and he thinks he needs a
delegate to update the UI, which is the wrong assumption if you take a look
at his code sample .

In his sample he runs 'countUpToaMillionOrSomething' on a spawned background
thread, while you do the actual work on the UI thread - something you
shouldn't do (unless it takes less than lets say a second) if you need to
keep the UI responsive, right?. More, you have to call DoEvents() to keep
the UI responsive, I guess you know where DoEvents comes from and where it
belongs, do you?

That's what he wanted. He needed to understand delegates, I assumed.

Strictly spoken, yes, but IMO OP's 'hidden real' question was "How to update
the UI" from a worker thread, while you showed how to use a delegate. I
could be wrong but, I'm affraid OP is getting even more confused when
looking at your code.
Anyway... I think you missed the part where i check Form.RequiresInvoke,
and if it is false, do the update directly.

Yes, but in this particular sample it's always true because its called from
a threadpool thread.
 
Yes thats right I need to understand how to pass a delegate to a new thread
I have created. I can do it synchronously but not asynchronously. So in the
example provided the 'BeginInvoke' command executes that on a seperate
thread using the threadpool, however Richard says:
------
You example would be much more real world if the worker thread was
performing the work and then passing the requests to update the progress bar
back to the UI thread via control.Invoke (or BeginInvoke which is preferable
in my book)
------

That is really what I was after. I have a sepereate static class that does
all the work. I need this class to receive the delegate but I dont know how
to send it there on the thread I created, which Id like to manage myself and
not have it automatically done (I heard DoEvents was evil in VB6, is it the
same for .NET?) . Im starting up my own single thread and not using the
"threadpool waitcallback" way of creating threads (havent learnt how to to
do those just yet). So why does the IDE tell me "Method name
expected" when I get to the following line of code:
thing.countUpToaMillionOrSomething(dlgate). What method name is it
expecting? I have created the delegate (which I understand is a wrapper and
points to the progress bar updater function I created on the main form).

Thanks for all your help,
Cheers,
Grant


Dave said:
Lol. Thanks for the feedback, but does anyone read the initial question
anymore??
Please could someone give me a simple exampe of how to get a delegate
passed to my worked class so that my main form can update its progress
bar?

That's what he wanted. He needed to understand delegates, I assumed.

Anyway... I think you missed the part where i check Form.RequiresInvoke,
and if it is false, do the update directly.
UpdateProgessCore is exactly what is sounds like... a method to update a
progress bar. How do I know he's able to do this in one line of code?
That's why it's a seperate method.

Encapsulation.

--
Dave Sexton
[email protected]
-----------------------------------------------------------------------
Willy Denoyette said:
Is there something particular you are trying to prove here?
You run 'DoSomeWork' on the main UI thread, in 'DoSomeWork' you call an
asynchronous delegate to run 'UpdateProgress', as this one runs on a
thread from the pool you have to marshal the call to 'UpdateProgressCore'
(using the synchronous Invoke) so it runs on the UI thread.
So basically, you are running a long task on the UI thread , call a
delegate to update the UI on another thread and then need to Invoke to
marshal the call to the UI is plain silly. No surprise you need to call
DoEvents.
Agreed, if you do not call DoEvents you'll consume all available pool
threads and crash (Invoke doesn't return as the messages don't get
dispatched) , but you shouldn't run the task on the UI thread in the
first place.


Willy.




Dave said:
Comment out Application.DoEvents and you'll see how it helps.

Has to do with the fact that Windows uses a "Message Loop" so method
invocations for WinForms controls aren't exactly "real-time". The
message loop is like a queue, meaning first-in first-out. Your whole
windows app depends on the messages from the queue reaching the main
window procedure in order to process events, such as
System.Windows.Forms.Form.Paint event. Without this message, the form
will never refresh, and neither will it's child controls (i.e. progress
bar). User actions are also messages, so the window would "freeze" up,
not allowing you to interact with it, while the "DoSomeWork" method is
executing on the main window thread.

In other words:
1. Application.Run starts a message loop
2. Your Form (main application window) processes messages on the loop
3. My method (DoSomeWork) blocks the thread, not allowing it to
accept messages while it is running
4. Application.DoEvents allows the Form to process messages currently
in the queue, effectively updating the Form while DoSomeWork is doing
some work :)



--
Dave Sexton
[email protected]
-----------------------------------------------------------------------
message That looks great - apart from I don't understand why you call
DoEvents - how does this help?

Regards

Richard Blewett - DevelopMentor
http://www.dotnetconsult.co.uk/weblog



nntp://news.microsoft.com/microsoft.public.dotnet.languages.csharp/<#[email protected]>

You don't need to use the Thread class to invoke the delegate
asynchronously, however, invoking it using BeginInvoke will execute
the method that the delegate points to on a ThreadPool thread. Also,
ProgressBar (and any other WinForms control) requires most of
its members to be executed/accessed on the thread that the control was
created on. To account for this requirement, a proper
example can't be too simple.

Here's the simplest approach to updating a progress bar aynchronously
in a WinForms app (the proper way). I'm assuming that each
method is contained by a class derived from System.Windows.Forms.Form:

private delegate void UpdateProgressInvoker(int Position);
private System.Windows.Forms.ProgressBar progressBar;

/// <summary>Test the progress bar asynchronous update code</summary>
public void DoSomeWork()
{
progressBar.Minimum = 0;
progressBar.Maximum = 100;

for (int i = 0; i < 10000; i++)
{
// Create a pointer to the UpdateProgress method
UpdateProgressInvoker del = new UpdateProgressInvoker(UpdateProgress);

// Invoke the method asynchronously
del.BeginInvoke((int) (i / 100), null, null);

// Tell the app to handle pending messages
// (so the form doesn't freeze and the progress bar is updated
visually)
Application.DoEvents();
}
}


/// <summary>
/// This method does not update the progress bar directly. Instead, it
ensures that the
/// <see cref="UpdateProgressCore" /> method (which actually does the
work) is executed on the
/// thread that the ProgressBar was created on.
/// </summary>
private void UpdateProgress(int Position)
{
// Check if the Form.InvokeRequired property is true. This will
indicate that
// the currently executing thread is not the thread that the
ProgressBar was created on.
// To update the progress bar synchronously, we will need to invoke the
method on the
// main thread.
// [this] must be a reference to a Form object.
if (!this.InvokeRequired)
{
// Create a pointer to the UpdateProgressCore method which performs the
actual update
UpdateProgressInvoker del = new
UpdateProgressInvoker(UpdateProgressCore);

// Invoke the method asynchronously on the main thread of the
application.
// By using Form.Invoke, we ensure that our progress bar will be
updated properly.
this.Invoke(del, new object[] { Position });
}
else
// Currently executing thread is the ProgressBar's thread,
// so update the progress bar normally
UpdateProgressCore(Position);
}

/// <summary>
/// Do not call this method directly. Instead, call <see
cref="UpdateProgress" />.
/// </summary>
private void UpdateProgressCore(int Position)
{
progressBar.Value = Position;
}


--
Dave Sexton
[email protected]
-----------------------------------------------------------------------
I am having great difficulty understanding this and any code samples I
find online are kilometres long and complicated to
understand...Please could someone give me a simple exampe of how to
get a delegate passed to my worked class so that my main form
can update its progress bar? I know it has something to do with
begininvoke and endinvoke etc, but I just need a simple sample to
understand the convention.


Code from my main form:
-----------------------------------
form1Delegate dlgate = new form1Delegate(IncreaseProgressBar);
//thing.countUpToaMillionOrSomething(new
form1Delegate(this.IncreaseProgressBar));
Thread thread = new Thread(new
ThreadStart(thing.countUpToaMillionOrSomething(dlgate)));
thread.Start();
-----------------------------------

Code from my worker class called 'thing'
-----------------------------------
public static void countUpToaMillionOrSomething(Form1.form1Delegate
myMethodDelegate)
{
int x = 0;
while ( x < 50)
{
Thread.Sleep(70);
x ++ ;
myMethodDelegate();
}
}
-----------------------------------


I can only get it to work synchronously with the following line:

thing.countUpToaMillionOrSomething(new
form1Delegate(this.IncreaseProgressBar));

If I try compile with the thread example above it spews about 'Method
name expected' and underlines the following bit of code:

thing.countUpToaMillionOrSomething(dlgate)

Any help greatly appreciated,
Thanks,
Grant





[microsoft.public.dotnet.languages.csharp]
 
Something like this:

using System.Runtime.Remoting.Messaging; .. for the AsyncCallback class

delegate void CountToAMillionDel(Form f);
delegate void UpdaterDel();

// Main form

void button1_Click(object sender, EventArgs e)
{
CountToAMillionDel d = new CountToAMillionDel(countUpToaMillionOrSomething);
// run the long running process on a worker thread
d.BeginInvoke(progressForm, new AsyncCallback(Callback), null); // the callback means we can call EndInvoke
}

void Callback(IAsyncResult ar)
{
AsyncResult a = (AsyncResult)ar;
CountToAMillionDel d = (CountToAMillionDel)a.AsyncDelegate;
d.EndInvoke(ar);
}

void countUpToaMillionOrSomething(Form f)
{
for(something which takes a while)
{
if( you need to update thte progress bar)
{
// From the worker thread update the UI by marshalling the update to the UI thread
f.BeginInvoke(newUpdaterDel(UpdateProgressBar), new object[]{}); // this is the Control.BeginInvoke member not Delegate.BeginInvoke
}
}
}

void UpdateProgressBar()
{
// perform the progress bar update
}

This should get you the behaviour you want. Be warned I've only used the Outlook compiler on this ;-) - I typed it into Outlook by hand so there may be minor typos, etc.

Regards

Richard Blewett - DevelopMentor
http://www.dotnetconsult.co.uk/weblog
http://www.dotnetconsult.co.uk

Yes thats right I need to understand how to pass a delegate to a new thread
I have created. I can do it synchronously but not asynchronously. So in the
example provided the 'BeginInvoke' command executes that on a seperate
thread using the threadpool, however Richard says:
------
You example would be much more real world if the worker thread was
performing the work and then passing the requests to update the progress bar
back to the UI thread via control.Invoke (or BeginInvoke which is preferable
in my book)
------

That is really what I was after. I have a sepereate static class that does
all the work. I need this class to receive the delegate but I dont know how
to send it there on the thread I created, which Id like to manage myself and
not have it automatically done (I heard DoEvents was evil in VB6, is it the
same for .NET?) . Im starting up my own single thread and not using the
"threadpool waitcallback" way of creating threads (havent learnt how to to
do those just yet). So why does the IDE tell me "Method name
expected" when I get to the following line of code:
thing.countUpToaMillionOrSomething(dlgate). What method name is it
expecting? I have created the delegate (which I understand is a wrapper and
points to the progress bar updater function I created on the main form).

Thanks for all your help,
Cheers,
Grant
 
The code I supplied was to illustrate how to use a delegate asynchronously, in a simple approach. I used a design pattern that
would allow the developer to call the "UpdateProgress" method from a class that has a reference to the form without caring about the
"logic" involved in updating the Form's controls.

Thread-Safety
Encapsulation
Win32 programming

Grant:

In my previous code sample I have illustrated how you can use a delegate. I'm sorry if it was unclear. I have attached a simpler
approach below.

The code below will also address this question:
thing.countUpToaMillionOrSomething(dlgate). What method name is it expecting?

Code example:

public delegate void DoSomething();

public void countUpToaMillionOrSomething(DoSomething ThingToDo)
{
// call the "ThingToDo" asynchronously
ThingToDo.BeginInvoke(null, null);
}


public void TargetOfInvocation()
{
Debug.WriteLine("Something.");
}


public void Test()
{
countUpToaMillionOrSomething(new DoSomething(TargetOfInvocation));

// Give the method some time to execute before the Debugger detaches
// (If you don't give it a long enough period of time, you may not see the output,
// yet the "TargetOfInvocation" method will be invoked regardless)
System.Threading.Thread.Sleep(1000);
}

--
Dave Sexton
[email protected]
-----------------------------------------------------------------------
Grant said:
Yes thats right I need to understand how to pass a delegate to a new thread I have created. I can do it synchronously but not
asynchronously. So in the example provided the 'BeginInvoke' command executes that on a seperate thread using the threadpool,
however Richard says:
------
You example would be much more real world if the worker thread was performing the work and then passing the requests to update the
progress bar back to the UI thread via control.Invoke (or BeginInvoke which is preferable in my book)
------

That is really what I was after. I have a sepereate static class that does all the work. I need this class to receive the delegate
but I dont know how to send it there on the thread I created, which Id like to manage myself and not have it automatically done (I
heard DoEvents was evil in VB6, is it the same for .NET?) . Im starting up my own single thread and not using the "threadpool
waitcallback" way of creating threads (havent learnt how to to do those just yet). So why does the IDE tell me "Method name
expected" when I get to the following line of code: thing.countUpToaMillionOrSomething(dlgate). What method name is it expecting?
I have created the delegate (which I understand is a wrapper and points to the progress bar updater function I created on the main
form).

Thanks for all your help,
Cheers,
Grant


Dave said:
Lol. Thanks for the feedback, but does anyone read the initial question anymore??
Please could someone give me a simple exampe of how to get a delegate passed to my worked class so that my main form can update
its progress bar?

That's what he wanted. He needed to understand delegates, I assumed.

Anyway... I think you missed the part where i check Form.RequiresInvoke, and if it is false, do the update directly.
UpdateProgessCore is exactly what is sounds like... a method to update a progress bar. How do I know he's able to do this in one
line of code? That's why it's a seperate method.

Encapsulation.

--
Dave Sexton
[email protected]
-----------------------------------------------------------------------
Willy Denoyette said:
Is there something particular you are trying to prove here?
You run 'DoSomeWork' on the main UI thread, in 'DoSomeWork' you call an asynchronous delegate to run 'UpdateProgress', as this
one runs on a thread from the pool you have to marshal the call to 'UpdateProgressCore' (using the synchronous Invoke) so it
runs on the UI thread.
So basically, you are running a long task on the UI thread , call a delegate to update the UI on another thread and then need to
Invoke to marshal the call to the UI is plain silly. No surprise you need to call DoEvents.
Agreed, if you do not call DoEvents you'll consume all available pool threads and crash (Invoke doesn't return as the messages
don't get dispatched) , but you shouldn't run the task on the UI thread in the first place.


Willy.




Comment out Application.DoEvents and you'll see how it helps.

Has to do with the fact that Windows uses a "Message Loop" so method invocations for WinForms controls aren't exactly
"real-time". The message loop is like a queue, meaning first-in first-out. Your whole windows app depends on the messages from
the queue reaching the main window procedure in order to process events, such as System.Windows.Forms.Form.Paint event. Without
this message, the form will never refresh, and neither will it's child controls (i.e. progress bar). User actions are also
messages, so the window would "freeze" up, not allowing you to interact with it, while the "DoSomeWork" method is executing on
the main window thread.

In other words:
1. Application.Run starts a message loop
2. Your Form (main application window) processes messages on the loop
3. My method (DoSomeWork) blocks the thread, not allowing it to accept messages while it is running
4. Application.DoEvents allows the Form to process messages currently in the queue, effectively updating the Form while
DoSomeWork is doing some work :)



--
Dave Sexton
[email protected]
-----------------------------------------------------------------------
That looks great - apart from I don't understand why you call DoEvents - how does this help?

Regards

Richard Blewett - DevelopMentor
http://www.dotnetconsult.co.uk/weblog



nntp://news.microsoft.com/microsoft.public.dotnet.languages.csharp/<#[email protected]>

You don't need to use the Thread class to invoke the delegate asynchronously, however, invoking it using BeginInvoke will
execute
the method that the delegate points to on a ThreadPool thread. Also, ProgressBar (and any other WinForms control) requires
most of
its members to be executed/accessed on the thread that the control was created on. To account for this requirement, a proper
example can't be too simple.

Here's the simplest approach to updating a progress bar aynchronously in a WinForms app (the proper way). I'm assuming that
each
method is contained by a class derived from System.Windows.Forms.Form:

private delegate void UpdateProgressInvoker(int Position);
private System.Windows.Forms.ProgressBar progressBar;

/// <summary>Test the progress bar asynchronous update code</summary>
public void DoSomeWork()
{
progressBar.Minimum = 0;
progressBar.Maximum = 100;

for (int i = 0; i < 10000; i++)
{
// Create a pointer to the UpdateProgress method
UpdateProgressInvoker del = new UpdateProgressInvoker(UpdateProgress);

// Invoke the method asynchronously
del.BeginInvoke((int) (i / 100), null, null);

// Tell the app to handle pending messages
// (so the form doesn't freeze and the progress bar is updated visually)
Application.DoEvents();
}
}


/// <summary>
/// This method does not update the progress bar directly. Instead, it ensures that the
/// <see cref="UpdateProgressCore" /> method (which actually does the work) is executed on the
/// thread that the ProgressBar was created on.
/// </summary>
private void UpdateProgress(int Position)
{
// Check if the Form.InvokeRequired property is true. This will indicate that
// the currently executing thread is not the thread that the ProgressBar was created on.
// To update the progress bar synchronously, we will need to invoke the method on the
// main thread.
// [this] must be a reference to a Form object.
if (!this.InvokeRequired)
{
// Create a pointer to the UpdateProgressCore method which performs the actual update
UpdateProgressInvoker del = new UpdateProgressInvoker(UpdateProgressCore);

// Invoke the method asynchronously on the main thread of the application.
// By using Form.Invoke, we ensure that our progress bar will be updated properly.
this.Invoke(del, new object[] { Position });
}
else
// Currently executing thread is the ProgressBar's thread,
// so update the progress bar normally
UpdateProgressCore(Position);
}

/// <summary>
/// Do not call this method directly. Instead, call <see cref="UpdateProgress" />.
/// </summary>
private void UpdateProgressCore(int Position)
{
progressBar.Value = Position;
}


--
Dave Sexton
[email protected]
-----------------------------------------------------------------------
I am having great difficulty understanding this and any code samples I find online are kilometres long and complicated to
understand...Please could someone give me a simple exampe of how to get a delegate passed to my worked class so that my main
form
can update its progress bar? I know it has something to do with begininvoke and endinvoke etc, but I just need a simple
sample to
understand the convention.


Code from my main form:
-----------------------------------
form1Delegate dlgate = new form1Delegate(IncreaseProgressBar);
//thing.countUpToaMillionOrSomething(new form1Delegate(this.IncreaseProgressBar));
Thread thread = new Thread(new ThreadStart(thing.countUpToaMillionOrSomething(dlgate)));
thread.Start();
-----------------------------------

Code from my worker class called 'thing'
-----------------------------------
public static void countUpToaMillionOrSomething(Form1.form1Delegate myMethodDelegate)
{
int x = 0;
while ( x < 50)
{
Thread.Sleep(70);
x ++ ;
myMethodDelegate();
}
}
-----------------------------------


I can only get it to work synchronously with the following line:

thing.countUpToaMillionOrSomething(new form1Delegate(this.IncreaseProgressBar));

If I try compile with the thread example above it spews about 'Method name expected' and underlines the following bit of
code:

thing.countUpToaMillionOrSomething(dlgate)

Any help greatly appreciated,
Thanks,
Grant





[microsoft.public.dotnet.languages.csharp]
 
Thanks for all your help with this. I had to change the 'progressForm' and
replace with 'this' which worked. I have a better understanding of this just
from looking at code.

Thanks again,
Grant

Richard Blewett said:
Something like this:

using System.Runtime.Remoting.Messaging; .. for the AsyncCallback class

delegate void CountToAMillionDel(Form f);
delegate void UpdaterDel();

// Main form

void button1_Click(object sender, EventArgs e)
{
CountToAMillionDel d = new
CountToAMillionDel(countUpToaMillionOrSomething);
// run the long running process on a worker thread
d.BeginInvoke(progressForm, new AsyncCallback(Callback), null); // the
callback means we can call EndInvoke
}

void Callback(IAsyncResult ar)
{
AsyncResult a = (AsyncResult)ar;
CountToAMillionDel d = (CountToAMillionDel)a.AsyncDelegate;
d.EndInvoke(ar);
}

void countUpToaMillionOrSomething(Form f)
{
for(something which takes a while)
{
if( you need to update thte progress bar)
{
// From the worker thread update the UI by marshalling the update to the
UI thread
f.BeginInvoke(newUpdaterDel(UpdateProgressBar), new object[]{}); // this
is the Control.BeginInvoke member not Delegate.BeginInvoke
}
}
}

void UpdateProgressBar()
{
// perform the progress bar update
}

This should get you the behaviour you want. Be warned I've only used the
Outlook compiler on this ;-) - I typed it into Outlook by hand so there
may be minor typos, etc.

Regards

Richard Blewett - DevelopMentor
http://www.dotnetconsult.co.uk/weblog
http://www.dotnetconsult.co.uk

Yes thats right I need to understand how to pass a delegate to a new
thread
I have created. I can do it synchronously but not asynchronously. So in
the
example provided the 'BeginInvoke' command executes that on a seperate
thread using the threadpool, however Richard says:
------
You example would be much more real world if the worker thread was
performing the work and then passing the requests to update the progress
bar
back to the UI thread via control.Invoke (or BeginInvoke which is
preferable
in my book)
------

That is really what I was after. I have a sepereate static class that does
all the work. I need this class to receive the delegate but I dont know
how
to send it there on the thread I created, which Id like to manage myself
and
not have it automatically done (I heard DoEvents was evil in VB6, is it
the
same for .NET?) . Im starting up my own single thread and not using the
"threadpool waitcallback" way of creating threads (havent learnt how to to
do those just yet). So why does the IDE tell me "Method name
expected" when I get to the following line of code:
thing.countUpToaMillionOrSomething(dlgate). What method name is it
expecting? I have created the delegate (which I understand is a wrapper
and
points to the progress bar updater function I created on the main form).

Thanks for all your help,
Cheers,
Grant
 
Dave, thanks for replying to my original post. Im sure there are many ways
to achieve the same thing and at the end of the day Ill learn whatever
works. Ive copied your code and Richards code, both of which have shown me
how delegates and asynchronous operations work.

Thanks for your help,
Grant

Dave said:
The code I supplied was to illustrate how to use a delegate
asynchronously, in a simple approach. I used a design pattern that would
allow the developer to call the "UpdateProgress" method from a class that
has a reference to the form without caring about the "logic" involved in
updating the Form's controls.

Thread-Safety
Encapsulation
Win32 programming

Grant:

In my previous code sample I have illustrated how you can use a delegate.
I'm sorry if it was unclear. I have attached a simpler approach below.

The code below will also address this question:
thing.countUpToaMillionOrSomething(dlgate). What method name is it
expecting?

Code example:

public delegate void DoSomething();

public void countUpToaMillionOrSomething(DoSomething ThingToDo)
{
// call the "ThingToDo" asynchronously
ThingToDo.BeginInvoke(null, null);
}


public void TargetOfInvocation()
{
Debug.WriteLine("Something.");
}


public void Test()
{
countUpToaMillionOrSomething(new DoSomething(TargetOfInvocation));

// Give the method some time to execute before the Debugger detaches
// (If you don't give it a long enough period of time, you may not see the
output,
// yet the "TargetOfInvocation" method will be invoked regardless)
System.Threading.Thread.Sleep(1000);
}

--
Dave Sexton
[email protected]
-----------------------------------------------------------------------
Grant said:
Yes thats right I need to understand how to pass a delegate to a new
thread I have created. I can do it synchronously but not asynchronously.
So in the example provided the 'BeginInvoke' command executes that on a
seperate thread using the threadpool, however Richard says:
------
You example would be much more real world if the worker thread was
performing the work and then passing the requests to update the progress
bar back to the UI thread via control.Invoke (or BeginInvoke which is
preferable in my book)
------

That is really what I was after. I have a sepereate static class that
does all the work. I need this class to receive the delegate but I dont
know how to send it there on the thread I created, which Id like to
manage myself and not have it automatically done (I heard DoEvents was
evil in VB6, is it the same for .NET?) . Im starting up my own single
thread and not using the "threadpool waitcallback" way of creating
threads (havent learnt how to to do those just yet). So why does the IDE
tell me "Method name
expected" when I get to the following line of code:
thing.countUpToaMillionOrSomething(dlgate). What method name is it
expecting? I have created the delegate (which I understand is a wrapper
and points to the progress bar updater function I created on the main
form).

Thanks for all your help,
Cheers,
Grant


Dave said:
Lol. Thanks for the feedback, but does anyone read the initial question
anymore??

Please could someone give me a simple exampe of how to get a delegate
passed to my worked class so that my main form can update its progress
bar?

That's what he wanted. He needed to understand delegates, I assumed.

Anyway... I think you missed the part where i check Form.RequiresInvoke,
and if it is false, do the update directly.
UpdateProgessCore is exactly what is sounds like... a method to update a
progress bar. How do I know he's able to do this in one line of code?
That's why it's a seperate method.

Encapsulation.

--
Dave Sexton
[email protected]
-----------------------------------------------------------------------
Is there something particular you are trying to prove here?
You run 'DoSomeWork' on the main UI thread, in 'DoSomeWork' you call an
asynchronous delegate to run 'UpdateProgress', as this one runs on a
thread from the pool you have to marshal the call to
'UpdateProgressCore' (using the synchronous Invoke) so it runs on the
UI thread.
So basically, you are running a long task on the UI thread , call a
delegate to update the UI on another thread and then need to Invoke to
marshal the call to the UI is plain silly. No surprise you need to call
DoEvents.
Agreed, if you do not call DoEvents you'll consume all available pool
threads and crash (Invoke doesn't return as the messages don't get
dispatched) , but you shouldn't run the task on the UI thread in the
first place.


Willy.




Comment out Application.DoEvents and you'll see how it helps.

Has to do with the fact that Windows uses a "Message Loop" so method
invocations for WinForms controls aren't exactly "real-time". The
message loop is like a queue, meaning first-in first-out. Your whole
windows app depends on the messages from the queue reaching the main
window procedure in order to process events, such as
System.Windows.Forms.Form.Paint event. Without this message, the form
will never refresh, and neither will it's child controls (i.e.
progress bar). User actions are also messages, so the window would
"freeze" up, not allowing you to interact with it, while the
"DoSomeWork" method is executing on the main window thread.

In other words:
1. Application.Run starts a message loop
2. Your Form (main application window) processes messages on the
loop
3. My method (DoSomeWork) blocks the thread, not allowing it to
accept messages while it is running
4. Application.DoEvents allows the Form to process messages
currently in the queue, effectively updating the Form while DoSomeWork
is doing some work :)



--
Dave Sexton
[email protected]
-----------------------------------------------------------------------
in message That looks great - apart from I don't understand why you call
DoEvents - how does this help?

Regards

Richard Blewett - DevelopMentor
http://www.dotnetconsult.co.uk/weblog



nntp://news.microsoft.com/microsoft.public.dotnet.languages.csharp/<#[email protected]>

You don't need to use the Thread class to invoke the delegate
asynchronously, however, invoking it using BeginInvoke will execute
the method that the delegate points to on a ThreadPool thread. Also,
ProgressBar (and any other WinForms control) requires most of
its members to be executed/accessed on the thread that the control
was created on. To account for this requirement, a proper
example can't be too simple.

Here's the simplest approach to updating a progress bar aynchronously
in a WinForms app (the proper way). I'm assuming that each
method is contained by a class derived from
System.Windows.Forms.Form:

private delegate void UpdateProgressInvoker(int Position);
private System.Windows.Forms.ProgressBar progressBar;

/// <summary>Test the progress bar asynchronous update code</summary>
public void DoSomeWork()
{
progressBar.Minimum = 0;
progressBar.Maximum = 100;

for (int i = 0; i < 10000; i++)
{
// Create a pointer to the UpdateProgress method
UpdateProgressInvoker del = new
UpdateProgressInvoker(UpdateProgress);

// Invoke the method asynchronously
del.BeginInvoke((int) (i / 100), null, null);

// Tell the app to handle pending messages
// (so the form doesn't freeze and the progress bar is updated
visually)
Application.DoEvents();
}
}


/// <summary>
/// This method does not update the progress bar directly. Instead,
it ensures that the
/// <see cref="UpdateProgressCore" /> method (which actually does the
work) is executed on the
/// thread that the ProgressBar was created on.
/// </summary>
private void UpdateProgress(int Position)
{
// Check if the Form.InvokeRequired property is true. This will
indicate that
// the currently executing thread is not the thread that the
ProgressBar was created on.
// To update the progress bar synchronously, we will need to invoke
the method on the
// main thread.
// [this] must be a reference to a Form object.
if (!this.InvokeRequired)
{
// Create a pointer to the UpdateProgressCore method which performs
the actual update
UpdateProgressInvoker del = new
UpdateProgressInvoker(UpdateProgressCore);

// Invoke the method asynchronously on the main thread of the
application.
// By using Form.Invoke, we ensure that our progress bar will be
updated properly.
this.Invoke(del, new object[] { Position });
}
else
// Currently executing thread is the ProgressBar's thread,
// so update the progress bar normally
UpdateProgressCore(Position);
}

/// <summary>
/// Do not call this method directly. Instead, call <see
cref="UpdateProgress" />.
/// </summary>
private void UpdateProgressCore(int Position)
{
progressBar.Value = Position;
}


--
Dave Sexton
[email protected]
-----------------------------------------------------------------------
I am having great difficulty understanding this and any code samples
I find online are kilometres long and complicated to
understand...Please could someone give me a simple exampe of how to
get a delegate passed to my worked class so that my main form
can update its progress bar? I know it has something to do with
begininvoke and endinvoke etc, but I just need a simple sample to
understand the convention.


Code from my main form:
-----------------------------------
form1Delegate dlgate = new form1Delegate(IncreaseProgressBar);
//thing.countUpToaMillionOrSomething(new
form1Delegate(this.IncreaseProgressBar));
Thread thread = new Thread(new
ThreadStart(thing.countUpToaMillionOrSomething(dlgate)));
thread.Start();
-----------------------------------

Code from my worker class called 'thing'
-----------------------------------
public static void countUpToaMillionOrSomething(Form1.form1Delegate
myMethodDelegate)
{
int x = 0;
while ( x < 50)
{
Thread.Sleep(70);
x ++ ;
myMethodDelegate();
}
}
-----------------------------------


I can only get it to work synchronously with the following line:

thing.countUpToaMillionOrSomething(new
form1Delegate(this.IncreaseProgressBar));

If I try compile with the thread example above it spews about
'Method name expected' and underlines the following bit of code:

thing.countUpToaMillionOrSomething(dlgate)

Any help greatly appreciated,
Thanks,
Grant





[microsoft.public.dotnet.languages.csharp]
 
Back
Top