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]