Hi, could somebody analyze a class and suggest what to do to avoid
hanging the class (thread) when the application calling it exits? (Other
than using background threads). This class is something similar to a
splash screen. Thanks
using System;
using System.Drawing;
using System.Windows.Forms;
using System.Threading;
using System.Reflection;
using System.IO;
namespace CF.GUI {
/// <summary>
/// Displays a "connecting" window with animation of signal sent
between two computers.
/// The window is shown only if a second has passed since it was called.
/// </summary>
/// <remarks>
/// Warning! Disables the parent form, if Hide() isn't called the
parent form will be frozen!
/// Always use try-finally block.</remarks>
/// <example>
/// ConnectionForm f = null;
/// try {
/// f = new ConnectionForm(this);
/// f.Show();
/// // do something in the main thread
/// } finally {
/// f.Hide();
/// f.Dispose();
/// f = null;
/// }
/// </example>
public class ConnectionForm : Form, IDisposable {
private Size size;
private Point computer1;
private Point computer2;
private Point computer1Attach;
private Point computer2Attach;
private Point textLocation;
private Rectangle invRect;
private bool modal;
/// <summary>
/// position of "signal" in the network
/// </summary>
private int signalPosition;
/// <summary>
/// length of the "signal"
/// </summary>
private const int signalLength = 10;
/// <summary>
/// in which direction does the "signal" travel
/// </summary>
private bool signalDirectionRight = true;
private Form owner = null;
private Icon icon;
private Thread threadShow;
private Thread threadAnimate;
private string caption;
public ConnectionForm(Form owner) {
try {
this.owner = owner;
this.owner = null;
this.size = new Size(200, 60);
this.computer1 = new Point(8, 15);
this.computer1Attach = new Point(28, 30);
this.computer2 = new Point(160, 15);
this.computer2Attach = new Point(180, 30);
this.textLocation = new Point(70, 4);
this.invRect = new Rectangle(computer1Attach.X, computer1Attach.Y -
1, computer2Attach.X, computer2Attach.Y + 1);
this.FormBorderStyle = FormBorderStyle.None;
this.BackColor = Color.White;
this.Cursor = Cursors.WaitCursor;
this.ControlBox = false;
this.HelpButton = false;
this.MaximizeBox = false;
this.MinimizeBox = false;
this.ShowInTaskbar = false;
this.Size = size;
this.StartPosition = FormStartPosition.CenterScreen;
this.Text = "Scania CF System";
this.TopLevel = true;
this.TopMost = true;
this.SetStyle(
ControlStyles.AllPaintingInWmPaint |
ControlStyles.DoubleBuffer |
ControlStyles.Opaque |
ControlStyles.UserPaint,
true);
caption = "Connecting...";
ICFModuleClient cf = CF.CFModuleSingleton.CFClient;
if (cf != null)
caption = cf.Captions.get("CF.GUI.ConnectingForm:Caption");
Assembly executingAssembly = Assembly.GetExecutingAssembly();
Stream resourceStream =
executingAssembly.GetManifestResourceStream( "CF.GUI.images.computer.ico" );
icon = new Icon(resourceStream);
} catch {}
}
~ConnectionForm() {
if (owner != null) {
try {
owner.Enabled = true;
} catch { }
owner = null;
}
}
// TODO: override or what?
public void Dispose() {
if (owner != null) {
try {
owner.Enabled = true;
} catch { }
owner = null;
}
base.Dispose(true);
}
/// <summary>
/// Displays the form. Starts new thread, so doesn't block
/// </summary>
public new void Show() {
Show(true);
}
/// <summary>
/// Displays the form. Starts new thread, so doesn't block
/// </summary>
public void Show(bool modal) {
this.modal = modal;
if (modal) owner = null;
if (owner != null) {
try {
owner.Enabled = false;
} catch { }
}
try {
threadShow = new Thread(new ThreadStart(threadShowRun));
threadShow.Start();
threadAnimate = new Thread(new ThreadStart(threadAnimateRun));
threadAnimate.Start();
} catch { }
}
/// <summary>
/// Closes the form
/// </summary>
public new void Hide() {
// TODO: invoke Hide()? It's called from an other thread I suppose?
Or not?
if (owner != null) {
try {
owner.Enabled = true;
} catch { }
owner = null;
}
int trials = 50;
bool success = false;
while (!false && (trials-- > 0) ) {
try {
this.Close();
success = true;
} catch {
Console.WriteLine("ERROR1");
}
if (!success) {
Thread.Sleep(20);
}
}
try {
threadAnimate.Abort();
threadShow.Abort();
this.Dispose();
} catch (Exception e) {
Console.WriteLine ("ERROR2" + e.Message);
}
}
private void threadShowRun() {
try {
// do not show window if time is less than one second
Thread.Sleep(1000);
if (modal)
this.ShowDialog();
else
this.Show();
} catch { }
}
private void threadAnimateRun() {
try {
signalPosition = computer1Attach.X;
signalDirectionRight = true;
while (true) {
if (signalDirectionRight) {
// send "signal"
if (signalPosition < computer2Attach.X) {
signalPosition += 6;
} else {
signalDirectionRight = false;
}
} else {
// send "signal"
if (signalPosition > computer1Attach.X) {
signalPosition -= 6;
} else {
signalDirectionRight = true;
}
}
Invoke(new MethodInvoker(Invalidate), new object[] {invRect});
Thread.Sleep(100);
}
} catch { }
}
private Bitmap backBuffer;
protected override void OnPaint(PaintEventArgs e) {
try {
if (backBuffer == null) {
backBuffer = new Bitmap(size.Width, size.Height);
}
Graphics g = Graphics.FromImage(backBuffer);
g.Clear(Color.White);
g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.None;
// draw border
Pen p = new Pen(Color.Black, 1);
g.DrawRectangle(p, 0, 0, size.Width - 1, size.Height - 1);
// draw text
g.DrawString(caption, new Font("Verdana", 7), Brushes.Black,
textLocation);
// draw animation
Pen p1 = new Pen(Color.Black, 3);
Pen p2 = new Pen(Color.White, 1);
g.DrawLine(p1, computer1Attach, computer2Attach);
int y = computer1Attach.Y;
g.DrawLine(p2, signalPosition, y, signalPosition - signalLength, y);
g.DrawIcon(icon, computer1.X, computer1.Y);
g.DrawIcon(icon, computer2.X, computer2.Y);
g.Dispose();
e.Graphics.DrawImageUnscaled(backBuffer, 0, 0);
} catch { }
}
protected override void OnPaintBackground(PaintEventArgs e) {
// don't allow the background to paint
}
}
}