PC Review


Reply
Thread Tools Rate Thread

Control.Invoke...Lots of controls and need help starting...

 
 
trint
Guest
Posts: n/a
 
      16th Sep 2005
Ok,
I start my thread job:

Thread t = new Thread(new
ThreadStart(invoicePrintingLongRunningCodeThread));
t.IsBackground = true;
t.Start();

There are lots of calls to controls and many happen in function calls
from invoicePrintingLongRunningCodeThread. I need just an example in
getting started with my thread job with Invoking so that this will
always run and not fizzle out by not doing it right.
Here is the thread job (it's not that long):

private void invoicePrintingLongRunningCodeThread ()
{
Hide();

//listBox1.Items.Add("Network : " + SystemInformation.Network );

if (button7.Text == "&Start Printing Invoices")
{
//temp name test
button7.Text = "&Invoices Are Being Processed";
///Run in separate thread

// ThreadStart myThreadDelegate = new
ThreadStart(ThreadFunction1.getOneAtATime);
// Thread thr1 = new Thread(myThreadDelegate);
// thr1.Start();
bool couNTer1 = false;
do
{
// Form1 findThread = new Form1();
label15.Text = ("0" + " Invoices Left to Print");
loadInvoiceContainer();
label15.Text = (Convert.ToString(Class1.cI) + " Invoices Left to
Print");
button7.Text = "&Watching for New Invoices";
if(Class1.cI > 0)
{
gotoForeach();
}
} while (couNTer1 == false);
}
else
{
// button7.Text = "&Start Printing Invoices";
PrinterBreaks = "BreaksOn";
// Thread tid1 = new Thread(new
ThreadStart(findThread.getOneAtATime ) );
// tid1.Abort();
}
}

Any help is appreciated.
Thanks,
Trint

 
Reply With Quote
 
 
 
 
=?Utf-8?B?VGF5bG9yTWljaGFlbEw=?=
Guest
Posts: n/a
 
      16th Sep 2005
As you are running on a non-UI thread you have to push any UI requests back
to the main UI thread. The InvokeRequired property on a Control specifies
whether an invoke is required or not. It really depends on the underlying
implementation of a Control whether or not it must be invoked but the general
"safe" rule is that you must interact with a control only on the main UI
thread. Some controls may handle this automatically in which case your code
would work just fine. For others the following skeleton implementation is
what you want:

delegate void StringDelegate ( Control target, string parm );
void SetText ( Control target, string text )
{
if (target.InvokeRequired)
target.Invoke(new StringDelegate(SetText), new object[] { target, text
});
else
target.Text = text;
}

The code basically determines if it is running on the UI thread. If it
isn't then in invokes the same method on the UI thread (Control.Invoke). If
it is on the UI thread then it simply sets the property. By changing the
delegate, Invoke arguments and the else-block you can modify this to work
with any property or method. Note that this is a blocking call. Use
BeginInvoke/EndInvoke to make it async.

Most controls don't implement this automatically for performance reasons but
I wouldn't be surprised if they don't migrate that way. For library code
that you write to encapsulate this stuff you should probably do this
automatically for your callers. For example instead of exposing a progress
bar on the status bar of your main form you should instead expose a method
from your main form to interact with the progress bar. In this case the
above logic should be encapsulated in the method you write.

As an aside I would also recommend that you minimize your cross-thread calls
and UI interaction. I'd recommend building an object that contains the
required UI changes and then invoke a method to update the UI with the object
contents when the thread is done (unless this is progress information). This
is especially true of list-style controls like ListBox and ListView. It
depends on how you want your UI to react though.

Hope this helps,
Michael Taylor - 9/16/05

"trint" wrote:

> Ok,
> I start my thread job:
>
> Thread t = new Thread(new
> ThreadStart(invoicePrintingLongRunningCodeThread));
> t.IsBackground = true;
> t.Start();
>
> There are lots of calls to controls and many happen in function calls
> from invoicePrintingLongRunningCodeThread. I need just an example in
> getting started with my thread job with Invoking so that this will
> always run and not fizzle out by not doing it right.
> Here is the thread job (it's not that long):
>
> private void invoicePrintingLongRunningCodeThread ()
> {
> Hide();
>
> //listBox1.Items.Add("Network : " + SystemInformation.Network );
>
> if (button7.Text == "&Start Printing Invoices")
> {
> //temp name test
> button7.Text = "&Invoices Are Being Processed";
> ///Run in separate thread
>
> // ThreadStart myThreadDelegate = new
> ThreadStart(ThreadFunction1.getOneAtATime);
> // Thread thr1 = new Thread(myThreadDelegate);
> // thr1.Start();
> bool couNTer1 = false;
> do
> {
> // Form1 findThread = new Form1();
> label15.Text = ("0" + " Invoices Left to Print");
> loadInvoiceContainer();
> label15.Text = (Convert.ToString(Class1.cI) + " Invoices Left to
> Print");
> button7.Text = "&Watching for New Invoices";
> if(Class1.cI > 0)
> {
> gotoForeach();
> }
> } while (couNTer1 == false);
> }
> else
> {
> // button7.Text = "&Start Printing Invoices";
> PrinterBreaks = "BreaksOn";
> // Thread tid1 = new Thread(new
> ThreadStart(findThread.getOneAtATime ) );
> // tid1.Abort();
> }
> }
>
> Any help is appreciated.
> Thanks,
> Trint
>
>

 
Reply With Quote
 
Jon Skeet
Guest
Posts: n/a
 
      16th Sep 2005
> There are lots of calls to controls and many happen in function calls
> from invoicePrintingLongRunningCodeThread. I need just an example in
> getting started with my thread job with Invoking so that this will
> always run and not fizzle out by not doing it right.
> Here is the thread job (it's not that long):


Again, I'd suggest looking at the sample code I linked to before:
http://www.pobox.com/~skeet/csharp/t...winforms.shtml

That gives an example of updating two labels, which is the kind of
thing you're
doing here. Basically, look through your code and identify everything
which
updates the UI - and make sure that runs in a thread-safe manner as per
the article.

Jon

 
Reply With Quote
 
=?Utf-8?B?RGViYXNpc2ggQm9zZSwgT3JhY2xlIENvcnA=?=
Guest
Posts: n/a
 
      16th Sep 2005
The correct way to deal with multiple threads and call back to main UI thread
in Winforms application is to use delegates to marshal data to UI threads.
It's also not recommended that "spawning threads from threads".

Take a look at the MSDN sample(Multithreaded Windows Forms Control Sample)
at follwoing UR
http://msdn.microsoft.com/library/de...rmsControl.asp
 
Reply With Quote
 
trint
Guest
Posts: n/a
 
      16th Sep 2005
Michael,
When it reaches gotoForeach();, from there a statusbar is constantly
updated and so are several label controls. I will have to somehow
address each call to a control correctly throughout the code.
>From the snipit I have given, it doesn't show the calls to update the

status bar or the text labels. Here is an another example of where I
need help in protecting this code:
public void PrinterStatusNPI7FC6D2()
{

string trayvalue = string.Empty;
///Tray 3
RFC1157.Mgmt mib = new RFC1157.Mgmt();
Snmp.ManagerSession sess=new
Snmp.ManagerSession(Class1.selectLJPrinter,"public");
Snmp.ManagerItem mi=new
Snmp.ManagerItem(sess,mib.OID("1.3.6.1.2.1.25.3.5.1.1.1"));
// listBox1.Items.Add("Tray 3".ToString());
// listBox1.Items.Add(mi.Value.ToString());
trayvalue = Convert.ToString(mi.Value);
label7.Text = string.Format("Printer Status: {0}",trayvalue);
if (trayvalue == "0")
{
PrinterBreaks = "BreaksOn";
Tray3 frmText3 = new Tray3();
frmText3.ShowDialog();
}

}

one more:

statusBarPanel2.Reset();
statusBarPanel2.Step();
statusBarPanel2.ProgressPosition = ((long)(Class1.toNerlOng));

Really would appreciate your help.
Thanks,
Trint

 
Reply With Quote
 
trint
Guest
Posts: n/a
 
      16th Sep 2005
Jon,

I am working with your example at this very moment.
How would I be able to use Control.Invoke with updating the status bar
here:

statusBarPanel2.Reset();
statusBarPanel2.Step();
statusBarPanel2.ProgressPosition = ((long)(Class1.toNerlOng));

Thanks,
Trint

 
Reply With Quote
 
Jon Skeet
Guest
Posts: n/a
 
      16th Sep 2005
Pass the "long" value to a method which does the reset, step and
progress position setting all within the same Control.Invoke call.

Jon

 
Reply With Quote
 
=?Utf-8?B?VGF5bG9yTWljaGFlbEw=?=
Guest
Posts: n/a
 
      16th Sep 2005
In your case I'd recommend creating a method on your form that accepts a
custom object (structure) that contains the label values and the progress bar
values. I'd then invoke this method in the secondary thread. This optimizes
your performance by making only a single cross-thread call per loop instead
of 3. Here is some sample code:

struct UpdateData
{
public UpdateData ( string status, long progress, params string[] items )
{
Status = status;
Progress = progress;
Items = items;
}
public string Status;
public string[] Items;
public long Progress;
}

class MyForm : Form
{
delegate void UpdateStatusDelegate ( UpdateData data );
void UpdateStatus ( UpdateData data )
{
if (InvokeRequired)
Invoke(new UpdateStatusDelegate(UpdateStatus), new object[] { data
});
else
{
foreach(string item in data.Items)
listbox1.Items.Add(item);

label7.Text = data.Status;

statusBarPanel2.Reset();
statusBarPanel2.Step();
statusBarPanel2.ProgressPosition = data.Progress;
};
}
}

public void PrinterStatusNPI7FC6D2()
{
string trayvalue = string.Empty;
///Tray 3
RFC1157.Mgmt mib = new RFC1157.Mgmt();
Snmp.ManagerSession sess=new
Snmp.ManagerSession(Class1.selectLJPrinter,"public");
Snmp.ManagerItem mi=new
Snmp.ManagerItem(sess,mib.OID("1.3.6.1.2.1.25.3.5.1.1.1"));

UpdateData data = new UpdateData();
string trayvalue = mi.Value.ToString();
data.Items = new string[] { "Tray 3", trayvalue };
data.Status = String.Concat("Printer Status: ", trayvalue);
f (trayvalue == "0")
{
//This could be bad
PrinterBreaks = "BreaksOn";
Tray3 frmText3 = new Tray3();
frmText3.ShowDialog();
}

//Maybe this is separate??
data.Progress = (long)Class1.toNerlOng;

//UI update
frmObj.UpdateStatus(data);
}

One thing that I'd be concerned about is that form creation in your
secondary thread. That is generally a bad idea because you are creating a
new form on a background thread. I'd try to do that some other way instead.

Michael Taylor - 9/16/05

"trint" wrote:

> Michael,
> When it reaches gotoForeach();, from there a statusbar is constantly
> updated and so are several label controls. I will have to somehow
> address each call to a control correctly throughout the code.
> >From the snipit I have given, it doesn't show the calls to update the

> status bar or the text labels. Here is an another example of where I
> need help in protecting this code:
> public void PrinterStatusNPI7FC6D2()
> {
>
> string trayvalue = string.Empty;
> ///Tray 3
> RFC1157.Mgmt mib = new RFC1157.Mgmt();
> Snmp.ManagerSession sess=new
> Snmp.ManagerSession(Class1.selectLJPrinter,"public");
> Snmp.ManagerItem mi=new
> Snmp.ManagerItem(sess,mib.OID("1.3.6.1.2.1.25.3.5.1.1.1"));
> // listBox1.Items.Add("Tray 3".ToString());
> // listBox1.Items.Add(mi.Value.ToString());
> trayvalue = Convert.ToString(mi.Value);
> label7.Text = string.Format("Printer Status: {0}",trayvalue);
> if (trayvalue == "0")
> {
> PrinterBreaks = "BreaksOn";
> Tray3 frmText3 = new Tray3();
> frmText3.ShowDialog();
> }
>
> }
>
> one more:
>
> statusBarPanel2.Reset();
> statusBarPanel2.Step();
> statusBarPanel2.ProgressPosition = ((long)(Class1.toNerlOng));
>
> Really would appreciate your help.
> Thanks,
> Trint
>
>

 
Reply With Quote
 
trint
Guest
Posts: n/a
 
      16th Sep 2005
Michael,
I don't know if this matters, but the frmText3.ShowDialog(); form is
like a message box (in the way it works) that just says "Tray 3 is out
of paper" and one button "Problem solved" that exits
frmText3.ShowDialog();.
If I had time at this point, I would certainly rather find some other
way of informing the user other than using controls.
Thanks,
Trint

 
Reply With Quote
 
=?Utf-8?B?VGF5bG9yTWljaGFlbEw=?=
Guest
Posts: n/a
 
      16th Sep 2005
MessageBox-style dialogs are "OK" and won't cause a crash normally however
you are somewhat limiting yourself. If you were to move away from
Thread.Start and instead go with the ThreadPool (with all its advantages)
then the dialog would cause a problem and potentially crash the app because
the ThreadPool threads are limited and your thread will block until the user
reacts. If your thread was started multiple times you could drain the
ThreadPool. Of course this may be just what you want. One thing that I have
done in the past in these cases is add a status box to my UI where I send
messages like this. It is better than a status panel because the information
isn't lost the next time I update the status. Instead the user sees that
there was a problem. Again it is a matter of requirements. So for now you
should be alright but you might want to look at an alternative in the future.

Michael Taylor - 9/16/05

"trint" wrote:

> Michael,
> I don't know if this matters, but the frmText3.ShowDialog(); form is
> like a message box (in the way it works) that just says "Tray 3 is out
> of paper" and one button "Problem solved" that exits
> frmText3.ShowDialog();.
> If I had time at this point, I would certainly rather find some other
> way of informing the user other than using controls.
> Thanks,
> Trint
>
>

 
Reply With Quote
 
 
 
Reply

Thread Tools
Rate This Thread
Rate This Thread:

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Using Multithreading with Controls (Control.Invoke, VB.NET) Mathijs Beentjes Microsoft Dot NET Compact Framework 2 3rd Jun 2005 06:09 PM
Can I line up lots of controls on a sheet at once? Robert Hargreaves Microsoft Excel Programming 2 1st Jun 2005 11:02 PM
Invoke send/receive when starting Outlook 2003? =?Utf-8?B?QnVkVg==?= Microsoft Outlook Discussion 5 24th May 2005 11:01 PM
trouble with report that has lots of controls =?Utf-8?B?dHc=?= Microsoft Access Reports 12 18th May 2005 11:07 PM
Forms with Lots of Controls Very Slow ShakeDoctor Microsoft Dot NET Compact Framework 2 21st Apr 2005 10:57 PM


Features
 

Advertising
 

Newsgroups
 


All times are GMT +1. The time now is 04:20 PM.