Borderless controls in a separate thread

  • Thread starter Thread starter Lionel Johnson
  • Start date Start date
L

Lionel Johnson

Hi:
I'm trying to put together a multi-threaded app where some
activity (actually moving waveform drawing) is happening
in a number of controls separate from the main thread. I
have tried 2 methods, both of which have some problems:

a. Start a new thread, create a Form containing the
control on which the moving waveform drawing is going to
take place and call Application.Run(frm1). Unfortunately,
if I set the FormBorderStyle to None (with the intention
of having the control fill the form), Application.Run
throws an "Out of Memory" Exception. If I leave the form
with a non-None border and try to set the FormBorderStyle
to None in the Load handler, I get the same exception.
However, if I see the border style to none some time later
(like in a Timer_Elapsed event), I can get rid of the
border with no ill effects.

b. Start a new thread, create a derived control in that
thread, call SetTopLevel(true) on that control and then
call Application.Run(). This works, except that the
resulting control has a Caption border.

Is there a way to create a control in a thread separate
from the main thread, that will receive messages and can
appear immediately without a border?

Thanks
Lionel
 
hello, Lionel,
I wrote a test as you said, and it works properly without that
exception. Could you give me some more information to reproduce the problem?
The following is my test code. You may create a new Windows
Application and replace the code with the following one.
click the New Thread button ,you will see a new form with no border.
In addition , It seems that your problem has some relation with the data
updating mechanism. I hope you can look into it
and give me more information about that exception.
Thanks,

using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.Threading;

namespace multithread_UI_update
{
/// <summary>
/// Summary description for Form1.
/// </summary>
public class Form1 : System.Windows.Forms.Form
{
private System.Windows.Forms.Button button1;
private Thread thread = null;
private Form2 form = null;
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.Container components = null;

public Form1()
{
//
// Required for Windows Form Designer support
//
InitializeComponent();

//
// TODO: Add any constructor code after InitializeComponent call
//
}

/// <summary>
/// Clean up any resources being used.
/// </summary>
protected override void Dispose( bool disposing )
{
if( disposing )
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}

#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.button1 = new System.Windows.Forms.Button();
this.SuspendLayout();
//
// button1
//
this.button1.Location = new System.Drawing.Point(16, 8);
this.button1.Name = "button1";
this.button1.Size = new System.Drawing.Size(144, 32);
this.button1.TabIndex = 0;
this.button1.Text = "New Thread";
this.button1.Click += new System.EventHandler(this.button1_Click);
//
// Form1
//
this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
this.ClientSize = new System.Drawing.Size(184, 61);
this.Controls.Add(this.button1);
this.Name = "Form1";
this.Text = "Form1";
this.Closed += new System.EventHandler(this.Form1_Closed);
this.ResumeLayout(false);

}
#endregion

/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.Run(new Form1());
}

private void button1_Click(object sender, System.EventArgs e)
{
thread = new Thread(new ThreadStart(ThreadProc));
thread.Start();
}

private void ThreadProc()
{
try
{
form = new Form2();
form.Show();
Application.Run(form);
}
finally
{
form.Dispose();
}
}

private void Form1_Closed(object sender, System.EventArgs e)
{
if (thread.IsAlive)
{
form.Close();
}
}
}
/// <summary>
/// Summary description for Form2.
/// </summary>
public class Form2 : System.Windows.Forms.Form
{
private System.Windows.Forms.Label label1;
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.Container components = null;

public Form2()
{
//
// Required for Windows Form Designer support
//
InitializeComponent();

//
// TODO: Add any constructor code after InitializeComponent call
//
}

/// <summary>
/// Clean up any resources being used.
/// </summary>
protected override void Dispose( bool disposing )
{
if( disposing )
{
if(components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.label1 = new System.Windows.Forms.Label();
this.SuspendLayout();
//
// label1
//
this.label1.Dock = System.Windows.Forms.DockStyle.Fill;
this.label1.Location = new System.Drawing.Point(0, 0);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(292, 273);
this.label1.TabIndex = 0;
this.label1.Text = "label1";
//
// Form2
//
this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
this.ClientSize = new System.Drawing.Size(292, 273);
this.Controls.Add(this.label1);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
this.Name = "Form2";
this.Text = "Form2";
this.ResumeLayout(false);

}
#endregion
}
}


regards,

Best regards,

Ying-Shen Yu[MSFT]
Microsoft Support Engineer

This posting is provided "AS IS" with no warranties, and confers no rights.
You assume all risk for your use. 2001 Microsoft Corporation. All rights
reserved.
 
Ying-Shen:

Thanks for your prompt reply! Your code does indeed work
and is very close to what I had. Unfortunately, I had code
in the Resize event for the second form that assumed the
presence of a Graphics object that I create in the Load
event. It appears that when the form is created without a
border, a Resize event occurs without the Load event
occuring and hence the Graphics object is not created in
time. In the case of a form with a border, the load event
is executed first and no resize event occurs until after
that point, by which time my Graphics object is available
and all is OK.

Now my only problem is that the individual forms (16 of
them in my application) show up in the Alt-Tab list
although I can successfully stop them appearing in the
task bar (setting the ShowInTaskbar property to false).

Please note that the reason that I am doing this is to
avoid having to marshal the realtime updates in these "sub-
forms" through the main UI thread since user interaction
could (and does) interfere with the realtime drawing.

I had another thought - although high level operations on
controls must be marshalled through the thread on which
the controls have been created, is it permissible to use
control.CreateGraphics()(say on a Panel control) and then
use the returned Graphics object in a separate thread? Of
course this would need to be coupled with an override of
the OnPaint method of the control with no contents
including no call to the base.OnPaint() to avoid
unexpected redrawing of the control. This appears to work,
but I wonder if it is legal. This approach would achieve
the same as with the separate forms previously discussed
without the disadvantage of having them appear in Alt-tab
list.

Once again, thanks for your help

Lionel

-----Original Message-----
hello, Lionel,
I wrote a test as you said, and it works properly without that
exception. Could you give me some more information to reproduce the problem?
The following is my test code. You may create a new Windows
Application and replace the code with the following one.
click the New Thread button ,you will see a new form with no border.
In addition , It seems that your problem has some relation with the data
updating mechanism. I hope you can look into it
and give me more information about that exception.
Thanks,

using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.Threading;

namespace multithread_UI_update
{
/// <summary>
/// Summary description for Form1.
/// </summary>
public class Form1 : System.Windows.Forms.Form
{
private System.Windows.Forms.Button button1;
private Thread thread = null;
private Form2 form = null;
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.Container components = null;

public Form1()
{
//
// Required for Windows Form Designer support
//
InitializeComponent();

//
// TODO: Add any constructor code after InitializeComponent call
//
}

/// <summary>
/// Clean up any resources being used.
/// </summary>
protected override void Dispose( bool disposing )
{
if( disposing )
{
if (components != null)
{
components.Dispose ();
}
}
base.Dispose( disposing );
}

#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.button1 = new System.Windows.Forms.Button();
this.SuspendLayout();
//
// button1
//
this.button1.Location = new System.Drawing.Point(16, 8);
this.button1.Name = "button1";
this.button1.Size = new System.Drawing.Size(144, 32);
this.button1.TabIndex = 0;
this.button1.Text = "New Thread";
this.button1.Click += new System.EventHandler(this.button1_Click);
//
// Form1
//
this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
this.ClientSize = new System.Drawing.Size(184, 61);
this.Controls.Add(this.button1);
this.Name = "Form1";
this.Text = "Form1";
this.Closed += new System.EventHandler(this.Form1_Closed);
this.ResumeLayout(false);

}
#endregion

/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.Run(new Form1());
}

private void button1_Click(object sender, System.EventArgs e)
{
thread = new Thread(new ThreadStart (ThreadProc));
thread.Start();
}

private void ThreadProc()
{
try
{
form = new Form2();
form.Show();
Application.Run(form);
}
finally
{
form.Dispose();
}
}

private void Form1_Closed(object sender, System.EventArgs e)
{
if (thread.IsAlive)
{
form.Close();
}
}
}
/// <summary>
/// Summary description for Form2.
/// </summary>
public class Form2 : System.Windows.Forms.Form
{
private System.Windows.Forms.Label label1;
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.Container components = null;

public Form2()
{
//
// Required for Windows Form Designer support
//
InitializeComponent();

//
// TODO: Add any constructor code after InitializeComponent call
//
}

/// <summary>
/// Clean up any resources being used.
/// </summary>
protected override void Dispose( bool disposing )
{
if( disposing )
{
if(components != null)
{
components.Dispose ();
}
}
base.Dispose( disposing );
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.label1 = new System.Windows.Forms.Label();
this.SuspendLayout();
//
// label1
//
this.label1.Dock = System.Windows.Forms.DockStyle.Fill;
this.label1.Location = new System.Drawing.Point(0, 0);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(292, 273);
this.label1.TabIndex = 0;
this.label1.Text = "label1";
//
// Form2
//
this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
this.ClientSize = new System.Drawing.Size(292, 273);
this.Controls.Add(this.label1);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
this.Name = "Form2";
this.Text = "Form2";
this.ResumeLayout(false);

}
#endregion
}
}


regards,

Best regards,

Ying-Shen Yu[MSFT]
Microsoft Support Engineer

This posting is provided "AS IS" with no warranties, and confers no rights.
You assume all risk for your use. 2001 Microsoft Corporation. All rights
reserved.

.
 
is it permissible to use
control.CreateGraphics()(say on a Panel control) and then
use the returned Graphics object in a separate thread?

Absolutely. You can even call CreateGraphics() from the secondary
thread -- the docs point out that CreateGraphics() is one of only four
Control methods that can safely be called from other threads. I'm doing
this in my RPG development kit (still in its infancy, but the
painting-from-a-thread code is well established and working well).

However, you do need to be careful: the control you're painting to
needs to have a valid window handle, from the time you call
CreateGraphics() until the time you dispose the Graphics object.
Otherwise you'll get sporadic exceptions. From my early experience, it
also seems that the control needs to be visible. My code takes the
cautious approach, and doesn't start the thread-based painting until the
control receives its first Paint event, and stops again when the form is
minimized. This may not be necessary, but I don't get exceptions, so
I'm happy. I also have code in the Closing event that waits for any
in-progress paint events to finish, before allowing the form to close.
The devil's in the details, and it took me a while to hit on the right
approach, but my current code has been running successfully for a couple
of weeks with no exceptions on shutdown. So it can be done.

If you'd like to see my code, let me know, and I can e-mail it to you.
 
Hello Lionel,
I think it's feasible to do drawing in a serperate UI worker thread,
but I suggest you creating the graphics object in new thread, because the
handle of the control(say panel) will not be changed after it created, and
the CreateGraphics is thread-safe according to the MSDN, then different
threads,can draw seperately with their own Graphics object. However, you
should be very careful if your worker thread uses any members of the
control,such as handling the resize event,closing event etc.
On your previous thought, I think it's possible to get rid of the border
by modifying the window style to toolwindow style (which will not show in
the taskbar or alt-tab list),and then process the WM_NCCALCSIZE and
WM_NCPAINT message of the form by yourself. In theory, there should be an
style set to make the toolwindow withou a border, but I haven't found it, I
will go on researching it and give you a example in the beginning of next
week, if I find it.

Thanks!


Kind regards,

Ying-Shen Yu [MSFT]
Microsoft Support Engineer

This posting is provided "AS IS" with no warranties, and confers no rights.
You assume all risk for your use. 2001 Microsoft Corporation. All rights
reserved.





From: "Lionel Johnson" <[email protected]>
Subject: RE: Borderless controls in a separate thread
Date: Thu, 7 Aug 2003 14:01:11 -0700
Newsgroups: microsoft.public.dotnet.framework.windowsforms



Ying-Shen:

Thanks for your prompt reply! Your code does indeed work
and is very close to what I had. Unfortunately, I had code
in the Resize event for the second form that assumed the
presence of a Graphics object that I create in the Load
event. It appears that when the form is created without a
border, a Resize event occurs without the Load event
occuring and hence the Graphics object is not created in
time. In the case of a form with a border, the load event
is executed first and no resize event occurs until after
that point, by which time my Graphics object is available
and all is OK.

Now my only problem is that the individual forms (16 of
them in my application) show up in the Alt-Tab list
although I can successfully stop them appearing in the
task bar (setting the ShowInTaskbar property to false).

Please note that the reason that I am doing this is to
avoid having to marshal the realtime updates in these "sub-
forms" through the main UI thread since user interaction
could (and does) interfere with the realtime drawing.

I had another thought - although high level operations on
controls must be marshalled through the thread on which
the controls have been created, is it permissible to use
control.CreateGraphics()(say on a Panel control) and then
use the returned Graphics object in a separate thread? Of
course this would need to be coupled with an override of
the OnPaint method of the control with no contents
including no call to the base.OnPaint() to avoid
unexpected redrawing of the control. This appears to work,
but I wonder if it is legal. This approach would achieve
the same as with the separate forms previously discussed
without the disadvantage of having them appear in Alt-tab
list.

Once again, thanks for your help

Lionel

-----Original Message-----
hello, Lionel,
I wrote a test as you said, and it works properly without that
exception. Could you give me some more information to reproduce the problem?
The following is my test code. You may create a new Windows
Application and replace the code with the following one.
click the New Thread button ,you will see a new form with no border.
In addition , It seems that your problem has some relation with the data
updating mechanism. I hope you can look into it
and give me more information about that exception.
Thanks,

using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.Threading;

namespace multithread_UI_update
{
/// <summary>
/// Summary description for Form1.
/// </summary>
public class Form1 : System.Windows.Forms.Form
{
private System.Windows.Forms.Button button1;
private Thread thread = null;
private Form2 form = null;
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.Container components = null;

public Form1()
{
//
// Required for Windows Form Designer support
//
InitializeComponent();

//
// TODO: Add any constructor code after InitializeComponent call
//
}

/// <summary>
/// Clean up any resources being used.
/// </summary>
protected override void Dispose( bool disposing )
{
if( disposing )
{
if (components != null)
{
components.Dispose ();
}
}
base.Dispose( disposing );
}

#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.button1 = new System.Windows.Forms.Button();
this.SuspendLayout();
//
// button1
//
this.button1.Location = new System.Drawing.Point(16, 8);
this.button1.Name = "button1";
this.button1.Size = new System.Drawing.Size(144, 32);
this.button1.TabIndex = 0;
this.button1.Text = "New Thread";
this.button1.Click += new System.EventHandler(this.button1_Click);
//
// Form1
//
this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
this.ClientSize = new System.Drawing.Size(184, 61);
this.Controls.Add(this.button1);
this.Name = "Form1";
this.Text = "Form1";
this.Closed += new System.EventHandler(this.Form1_Closed);
this.ResumeLayout(false);

}
#endregion

/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.Run(new Form1());
}

private void button1_Click(object sender, System.EventArgs e)
{
thread = new Thread(new ThreadStart (ThreadProc));
thread.Start();
}

private void ThreadProc()
{
try
{
form = new Form2();
form.Show();
Application.Run(form);
}
finally
{
form.Dispose();
}
}

private void Form1_Closed(object sender, System.EventArgs e)
{
if (thread.IsAlive)
{
form.Close();
}
}
}
/// <summary>
/// Summary description for Form2.
/// </summary>
public class Form2 : System.Windows.Forms.Form
{
private System.Windows.Forms.Label label1;
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.Container components = null;

public Form2()
{
//
// Required for Windows Form Designer support
//
InitializeComponent();

//
// TODO: Add any constructor code after InitializeComponent call
//
}

/// <summary>
/// Clean up any resources being used.
/// </summary>
protected override void Dispose( bool disposing )
{
if( disposing )
{
if(components != null)
{
components.Dispose ();
}
}
base.Dispose( disposing );
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.label1 = new System.Windows.Forms.Label();
this.SuspendLayout();
//
// label1
//
this.label1.Dock = System.Windows.Forms.DockStyle.Fill;
this.label1.Location = new System.Drawing.Point(0, 0);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(292, 273);
this.label1.TabIndex = 0;
this.label1.Text = "label1";
//
// Form2
//
this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
this.ClientSize = new System.Drawing.Size(292, 273);
this.Controls.Add(this.label1);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
this.Name = "Form2";
this.Text = "Form2";
this.ResumeLayout(false);

}
#endregion
}
}


regards,

Best regards,

Ying-Shen Yu[MSFT]
Microsoft Support Engineer

This posting is provided "AS IS" with no warranties, and confers no rights.
You assume all risk for your use. 2001 Microsoft Corporation. All rights
reserved.

.
 
Joe:

Thanks for the reply and all of the additional useful
information - its probably saved me an awful lot of time.
If it is not too much trouble, I'll take up your offer to
peek at the pertinent parts of your code - it will help to
cement some of the ideas.

Thanks very much

Lionel
 
Ying-Shen:

Thanks for the additional information.

I looked further at your suggestion for using a toolwindow
style. Overrode WndProc() and did an immediate return
without calling the base.WndProc() for WM_NCCALCSIZE and
WM_NCPAINT and the border disappeared while the form
stayed out of the Alt-Tab and taskbar list.

Thanks

Lionel
-----Original Message-----
Hello Lionel,
I think it's feasible to do drawing in a serperate UI worker thread,
but I suggest you creating the graphics object in new thread, because the
handle of the control(say panel) will not be changed after it created, and
the CreateGraphics is thread-safe according to the MSDN, then different
threads,can draw seperately with their own Graphics object. However, you
should be very careful if your worker thread uses any members of the
control,such as handling the resize event,closing event etc.
On your previous thought, I think it's possible to get rid of the border
by modifying the window style to toolwindow style (which will not show in
the taskbar or alt-tab list),and then process the WM_NCCALCSIZE and
WM_NCPAINT message of the form by yourself. In theory, there should be an
style set to make the toolwindow withou a border, but I haven't found it, I
will go on researching it and give you a example in the beginning of next
week, if I find it.

Thanks!


Kind regards,

Ying-Shen Yu [MSFT]
Microsoft Support Engineer

This posting is provided "AS IS" with no warranties, and confers no rights.
You assume all risk for your use. 2001 Microsoft Corporation. All rights
reserved.





From: "Lionel Johnson" <[email protected]>
Subject: RE: Borderless controls in a separate thread
Date: Thu, 7 Aug 2003 14:01:11 -0700
Newsgroups: microsoft.public.dotnet.framework.windowsforms



Ying-Shen:

Thanks for your prompt reply! Your code does indeed work
and is very close to what I had. Unfortunately, I had code
in the Resize event for the second form that assumed the
presence of a Graphics object that I create in the Load
event. It appears that when the form is created without a
border, a Resize event occurs without the Load event
occuring and hence the Graphics object is not created in
time. In the case of a form with a border, the load event
is executed first and no resize event occurs until after
that point, by which time my Graphics object is available
and all is OK.

Now my only problem is that the individual forms (16 of
them in my application) show up in the Alt-Tab list
although I can successfully stop them appearing in the
task bar (setting the ShowInTaskbar property to false).

Please note that the reason that I am doing this is to
avoid having to marshal the realtime updates in these "sub-
forms" through the main UI thread since user interaction
could (and does) interfere with the realtime drawing.

I had another thought - although high level operations on
controls must be marshalled through the thread on which
the controls have been created, is it permissible to use
control.CreateGraphics()(say on a Panel control) and then
use the returned Graphics object in a separate thread? Of
course this would need to be coupled with an override of
the OnPaint method of the control with no contents
including no call to the base.OnPaint() to avoid
unexpected redrawing of the control. This appears to work,
but I wonder if it is legal. This approach would achieve
the same as with the separate forms previously discussed
without the disadvantage of having them appear in Alt-tab
list.

Once again, thanks for your help

Lionel

-----Original Message-----
hello, Lionel,
I wrote a test as you said, and it works properly without that
exception. Could you give me some more information to reproduce the problem?
The following is my test code. You may create a
new
Windows
Application and replace the code with the following one.
click the New Thread button ,you will see a new form
with
no border.
In addition , It seems that your problem has some relation with the data
updating mechanism. I hope you can look into it
and give me more information about that exception.
Thanks,

using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.Threading;

namespace multithread_UI_update
{
/// <summary>
/// Summary description for Form1.
/// </summary>
public class Form1 : System.Windows.Forms.Form
{
private System.Windows.Forms.Button button1;
private Thread thread = null;
private Form2 form = null;
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.Container components = null;

public Form1()
{
//
// Required for Windows Form Designer support
//
InitializeComponent();

//
// TODO: Add any constructor code after InitializeComponent call
//
}

/// <summary>
/// Clean up any resources being used.
/// </summary>
protected override void Dispose( bool disposing )
{
if( disposing )
{
if (components != null)
{
components.Dispose ();
}
}
base.Dispose( disposing );
}

#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.button1 = new System.Windows.Forms.Button();
this.SuspendLayout();
//
// button1
//
this.button1.Location = new System.Drawing.Point(16, 8);
this.button1.Name = "button1";
this.button1.Size = new System.Drawing.Size(144, 32);
this.button1.TabIndex = 0;
this.button1.Text = "New Thread";
this.button1.Click += new System.EventHandler(this.button1_Click);
//
// Form1
//
this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
this.ClientSize = new System.Drawing.Size(184, 61);
this.Controls.Add(this.button1);
this.Name = "Form1";
this.Text = "Form1";
this.Closed += new System.EventHandler(this.Form1_Closed);
this.ResumeLayout(false);

}
#endregion

/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.Run(new Form1());
}

private void button1_Click(object sender, System.EventArgs e)
{
thread = new Thread(new ThreadStart (ThreadProc));
thread.Start();
}

private void ThreadProc()
{
try
{
form = new Form2();
form.Show();
Application.Run(form);
}
finally
{
form.Dispose();
}
}

private void Form1_Closed(object sender, System.EventArgs e)
{
if (thread.IsAlive)
{
form.Close();
}
}
}
/// <summary>
/// Summary description for Form2.
/// </summary>
public class Form2 : System.Windows.Forms.Form
{
private System.Windows.Forms.Label label1;
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.Container components = null;

public Form2()
{
//
// Required for Windows Form Designer support
//
InitializeComponent();

//
// TODO: Add any constructor code after InitializeComponent call
//
}

/// <summary>
/// Clean up any resources being used.
/// </summary>
protected override void Dispose( bool disposing )
{
if( disposing )
{
if(components != null)
{
components.Dispose ();
}
}
base.Dispose( disposing );
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.label1 = new System.Windows.Forms.Label();
this.SuspendLayout();
//
// label1
//
this.label1.Dock = System.Windows.Forms.DockStyle.Fill;
this.label1.Location = new System.Drawing.Point(0, 0);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(292, 273);
this.label1.TabIndex = 0;
this.label1.Text = "label1";
//
// Form2
//
this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
this.ClientSize = new System.Drawing.Size(292, 273);
this.Controls.Add(this.label1);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
this.Name = "Form2";
this.Text = "Form2";
this.ResumeLayout(false);

}
#endregion
}
}


regards,

Best regards,

Ying-Shen Yu[MSFT]
Microsoft Support Engineer

This posting is provided "AS IS" with no warranties, and confers no rights.
You assume all risk for your use. 2001 Microsoft Corporation. All rights
reserved.

.

.
 
I'm posting this in the NG in case the code would help anyone else out...

I just posted my multithreaded-painting code on my Web site. Go to
http://www.excastle.com/Tyler/ and scroll to the bottom of the page, and
click "Download Tyler technology preview demo #1".

The parts that will probably interest you most are the SessionWindow and
the SessionViewer. The SessionWindow mostly just passes some
notifications (minimizing, closing) to the SessionViewer. The
SessionViewer (which is a Control parented to the SessionWindow) does
all the work of running a timer, locking critical sections as needed,
etc. It has a property which I somewhat whimsically named "Happy",
which determines whether painting can safely occur at this point in
time: if the viewer is happy, it's safe for threads to paint. Happy
starts off false, gets set to true when the SessionViewer gets its first
paint message, then gets set back to false when the SessionWindow is
minimized or closed. The Happy setter has a lock, which makes sure the
flag won't actually get changed until any paint-operation-in-progress
runs to completion. In turn, this ensures that the form can't be closed
while painting is in progress.

All my rendering is double-buffered. The locking mechanisms reflect
this -- there are more stringent critical-section checks around the
copy-to-screen operation, since that's where the cross-thread
CreateGraphics() actually happens.

If you have any questions about the code (I'm sure I could have
documented some of it better, especially as regards *why* I did things a
certain way), let me know -- either post here, or e-mail me. Hope this
helps!
 
Joe:
Thanks - much appreciated
Lionel
-----Original Message-----
I'm posting this in the NG in case the code would help anyone else out...

I just posted my multithreaded-painting code on my Web site. Go to
http://www.excastle.com/Tyler/ and scroll to the bottom of the page, and
click "Download Tyler technology preview demo #1".
[snip]
 
Back
Top