William,
I want to thank you for all you're help, you managed to get me on the
right track. I have solved the problem by foing the following :
-----------------------------------------------------------------------------------------------------------------------
// Used to store the nodes as they are populated
private Stack<TreeMenuNode> tn = new Stack<TreeMenuNode>();
private void frmMenuMaint_Load(object sender, EventArgs e)
{
this.Visible = false;
Thread _workerThread = new Thread(loadMenuTree);
_workerThread.Start();
using (Utilties.frmLogin frm = new Utilties.frmLogin(......)
{
frm.ShowDialog();
if (frm.DialogResult == DialogResult.OK)
{
this.Visible = true;
}
else
{
MessageBox.Show(.......);
Application.Exit();
}
}
try
{
// If the thread has not finished yet
// wait up to 30 secs for it to complete
if (_workerThread.IsAlive)
_workerThread.Join(30000);
} catch (Exception ex)
{
// Something has gone wrong
MessageBox.Show(......);
ev.WriteEntry(.......);
Application.Exit();
}
// Now add the nodes to the UI
lock (typeof(Stack<TreeMenuNode>))
{
while (tn.Count > 0)
tvMenus.Nodes.Add((TreeMenuNode)tn.Pop());
}
In essece the started Background thread finds all the top level nodes
(TreeMenuNodes in my case -- Inherited from TreeNodes), the task builds each
node and all its siblings attached to it, it then locks the stack var and
pushes the node onto it. This will repeat for each top level node defined
(in my case only 6 at the moment). When the user is logged on, I check to
see of the task has finished, if not block on the task for up to 30sec
(ample time). When the task is done, i just pop the nodes of the stack and
add them to the UI on the UI thread. I think this is the simplest safest
solution.
If you are interested I also got good info from the following 3 URLs
http://weblogs.asp.net/justin_rogers/articles/126345.aspx
http://code.snapstream.com/mediawiki/index.php/How_to_Update_UI_From_Background_Thread
http://msevents.microsoft.com/CUI/EventDetail.aspx?EventID=1032252816&Culture=en-US
Thank you again for you're invaluable assistance,
Jamie
William Stacey said:
Couple issues here I think I see. Your worker thread is not actually
doing
much here as you turn around and Invoke right way. Everything in the
Invoke{} is being done on the UI thread so it is blocking other UI
events -
that must be the issue you see.
If possible, you want to refactor your work out from your UI work. In
your
Thread, do the work loop and Invoke only the UI updates.
Such as
new Thread(delegate
{
while(true)
{
// Read line 1.
// Calc
if ( done )
break;
// Update UI
this.Invoke((ThreadStart)delegate()
{
this.treeview.update(xyz)/
}
}
}).Start();
frm.ShowDialog();
...
--
William Stacey [MVP]
| This is the Form Load Code
|
| private void frmMenuMaint_Load(object sender, EventArgs e)
| {
| // Hide the Main form (this has the Treeviews on this form
| this.Visible = false;
| // Create an instance of the Login Form
| using (Utilties.frmLogin frm = new
|
Utilties.frmLogin(ConfigurationManager.ConnectionStrings["Eden_POS_Management.Properties.Settings.HotelConnectionString"].ConnectionString))
| {
| new Thread(delegate()
| {
| this.Invoke((ThreadStart)delegate()
| {
| // This class performs the intense loading of the
| tree view
| // It initialy perofms a
| // tvMenus.SuspendLayout();
| // tv.BeginUpdate();
| // and resumes them on completion
| LoadTreeViews lt = new LoadTreeViews();
| lt.loadMenuTree(Plans, tvMenus);
| });
| }).Start();
| Thread.Sleep(150); // Doesn;t seem to make any
| difference
| // Validate the User, the Dialog will only return the OK
| result if the User Credentials are vaidated
| // This is the dialog that is Painting Slowly, it paints
| immediatley if I dont have the Load Treeview
| // therefor there is nothing slowing it down in this
| dialog
| frm.ShowDialog();
| if (frm.DialogResult == DialogResult.OK)
| {
| this.Visible = true;
| }
| else
| {
| MessageBox.Show("Invalid Login Attempt\nPlease
Contact
| you're System Administrator", "Data Error", MessageBoxButtons.OK,
| MessageBoxIcon.Error);
| Application.Exit();
| }
| }
| }
|
| Thank you very much for you're continued input, I'll buy you a beer or 2
if
| we ever get that conference together in Thailand .......
|
| Jamie
|
| | > Without seeing any code, maybe a sleep(50) before the thread starts
the
| > loop
| > to give the dialog a chance to display.
| >
| > --
| > William Stacey [MVP]
| >
| > | > |I already Suspend the Updates on the UI adn Suspend Layout. I cannot
move
| > | this thread start to after the dialog display as it is a ShowDailog,
| > which
| > | means the thread will not start until the user has been validated,
which
| > | takes away the whole point of running this update on another thread.
| > |
| > | Jamie
| > | | > | > Maybe wait to start the thread after your dialog is displayed.
| > Sounds
| > | > like
| > | > maybe the thread is doing much work and not allowing UI events.
Also
| > | > Suspend updates while building the UI on the hidden form and
Resume
| > | > updates
| > | > on the control after updates are done.
| > | >
| > | > --
| > | > William Stacey [MVP]
| > | >
| > | > | > | > | Thanks for the info William,
| > | > | I have implemented this model and yes it does work, but it is
| > causing
| > | > me
| > | > a
| > | > | little visual problem.
| > | > |
| > | > | What I do at startup is start the other thread as described in
the
| > model
| > | > you
| > | > | provided me, I hide the main form (which has the treeviews on
it)
| > and
| > | > diaply
| > | > | a login dialog.
| > | > | What is happening now is that it see,s to delay the the painting
o
f
| > the
| > | > | login dialog i.e. the borders draw with a plain white background
in
| > the
| > | > | dilaog then about 2 secs later the dilaog fills.
| > | > |
| > | > | Any ideas?
| > | > |
| > | > | Jamie
| > | > | | > | > | >I have an application that creates a pretty intensive TreeView
at
| > | > startup
| > | > | >time. I had the program running on a single thread sucessfully,
but
| > the
| > | > | >startup time was a bit excessive. When the application starts
up
it
| > is
| > | > a
| > | > | >requirement for the user to log on, so in my magical wisdom, I
| > thought
| > | > | >shove all this processing on another thread, so it loads while
the
| > user
| > | > | >logs on. I have all the code running on the thread OK, but I
cannot
| > | > figure
| > | > | >out how to return the data to the main thread so that I can
update
| > the
| > | > UI
| > | > | >from the main thread.
| > | > | >
| > | > | > In the BackgroundWorker task I have created a new TreeView
that
is
| > not
| > | > | > attached to any UI. I build this in the background, I then
| > attempted
| > | > to
| > | > | > Pass this back through an MSMQ Queue, but unfortunately the
| > TreeView
| > | > class
| > | > | > in non Serializable so the Queue.Send fails.
| > | > | >
| > | > | > Can someone please explain to the best way to return this data
to
| > the
| > | > main
| > | > | > thread.
| > | > | >
| > | > | > Thanks in advance
| > | > | >
| > | > | > Jamie
| > | > | >
| > | > |
| > | > |
| > | >
| > | >
| > |
| > |
| >
| >
|
|