T
Tony Johansson
Hello!
Below is a complete program that works fine in release mode but cause run
time errror in debug mode
because of "Cross-thread operation not valid: Control 'digital' accessed
from a thread
other than the thread it was created on."
The windows program below consist of these 4 classes
1. Program
2. Form
3. Clock
4 Ticker
Now to my questions.
Info the program below is a copy from a book called Visual studio 2005 from
Microsoft.
1. The first question is that the program below works fine in release mode
but cause
run time error in debug mode. So because of that I assume that the thread
handling must be different
between debug mode and release mode?
2.Is it always advisable to fix run time error of the kind that I have in
this program?
3. My third question is how do I fix the program with the same
functionallity
which mean that I can subscribe to the event and unsubscribe to the event
without causing
run time error?
4. Assume I have written a program and only run it in release mode because
it works as expected. In this case I will never
discover that there exist a problem with thead handling as in my example. So
is the solution to find problem
with thread to always run these program through the debugger?
The first class is the Program where the main is located
// *** Program ****
#region Using directives
using System;
using System.Collections.Generic;
using System.Windows.Forms;
#endregion
namespace Delegates
{
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.Run(new Form1());
}
}
} //end class Program
The second class is the Form1 class
// Form1 start
#region Using directives
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Windows.Forms;
#endregion
namespace Delegates
{
partial class Form1 : Form
{
private Clock clock;
public Form1()
{
InitializeComponent();
clock = new Clock(digital);
}
private void start_Click(object sender, System.EventArgs e)
{ clock.Start(); }
private void stop_Click(object sender, System.EventArgs e)
{ clock.Stop(); }
} // end class Form1
}
Here I have the Form1.designer part
// ** Form1 Designer ***
Namespace Delegates
{
partial class Form1
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
protected override void Dispose(bool disposing)
{
if (disposing && (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.stop = new System.Windows.Forms.Button();
this.start = new System.Windows.Forms.Button();
this.digital = new System.Windows.Forms.TextBox();
this.SuspendLayout();
//
// stop
//
this.stop.Location = new System.Drawing.Point(144, 67);
this.stop.Name = "stop";
this.stop.Size = new System.Drawing.Size(48, 23);
this.stop.TabIndex = 5;
this.stop.Text = "Stop";
this.stop.Click += new System.EventHandler(this.stop_Click);
//
// start
//
this.start.Location = new System.Drawing.Point(72, 67);
this.start.Name = "start";
this.start.Size = new System.Drawing.Size(56, 23);
this.start.TabIndex = 4;
this.start.Text = "Start";
this.start.Click += new System.EventHandler(this.start_Click);
//
// digital
//
this.digital.Enabled = false;
this.digital.Font = new System.Drawing.Font("Courier New",
20.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point,
((byte)(0)));
this.digital.Location = new System.Drawing.Point(56, 19);
this.digital.Name = "digital";
this.digital.Size = new System.Drawing.Size(152, 38);
this.digital.TabIndex = 3;
this.digital.Text = "04:11:34";
this.digital.TextAlign =
System.Windows.Forms.HorizontalAlignment.Center;
//
// Form1
//
this.ClientSize = new System.Drawing.Size(264, 109);
this.Controls.Add(this.stop);
this.Controls.Add(this.start);
this.Controls.Add(this.digital);
this.Name = "Form1";
this.Text = "Digital Clock";
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.Button stop;
private System.Windows.Forms.Button start;
private System.Windows.Forms.TextBox digital;
}
}
The third class is the Clock class
// ** Clock ***
using System.Windows.Forms;
namespace Delegates
{
class Clock
{
private Ticker pulsed = new Ticker();
private TextBox display;
public Clock(TextBox display)
{ this.display = display; }
public void Start()
{ pulsed.tick += new Ticker.Tick(RefreshTime); }
public void Stop()
{ pulsed.tick -= new Ticker.Tick(RefreshTime); }
private void RefreshTime(int hh, int mm, int ss)
{ display.Text = string.Format("{02}:{12}:{22}", hh, mm,
); }
}
//Start class Ticker
Namespace Delegates
{
using System.Timers;
class Ticker
{
public delegate void Tick(int hh, int mm, int ss);
public event Tick tick;
private Timer ticking = new Timer();
public Ticker()
{
ticking.Elapsed += new ElapsedEventHandler(OnTimedElapsed);
ticking.Interval = 1000;
ticking.Enabled = true;
}
private void Notify(int hours, int minutes, int seconds)
{ if (tick != null) tick(hours, minutes, seconds); }
private void OnTimedElapsed(object source, ElapsedEventArgs args)
{
int hh = args.SignalTime.Hour;
int mm = args.SignalTime.Minute;
int ss = args.SignalTime.Second;
Notify(hh, mm, ss); // call notify
}
}
} // end class Ticker
Below is a complete program that works fine in release mode but cause run
time errror in debug mode
because of "Cross-thread operation not valid: Control 'digital' accessed
from a thread
other than the thread it was created on."
The windows program below consist of these 4 classes
1. Program
2. Form
3. Clock
4 Ticker
Now to my questions.
Info the program below is a copy from a book called Visual studio 2005 from
Microsoft.
1. The first question is that the program below works fine in release mode
but cause
run time error in debug mode. So because of that I assume that the thread
handling must be different
between debug mode and release mode?
2.Is it always advisable to fix run time error of the kind that I have in
this program?
3. My third question is how do I fix the program with the same
functionallity
which mean that I can subscribe to the event and unsubscribe to the event
without causing
run time error?
4. Assume I have written a program and only run it in release mode because
it works as expected. In this case I will never
discover that there exist a problem with thead handling as in my example. So
is the solution to find problem
with thread to always run these program through the debugger?
The first class is the Program where the main is located
// *** Program ****
#region Using directives
using System;
using System.Collections.Generic;
using System.Windows.Forms;
#endregion
namespace Delegates
{
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.Run(new Form1());
}
}
} //end class Program
The second class is the Form1 class
// Form1 start
#region Using directives
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Windows.Forms;
#endregion
namespace Delegates
{
partial class Form1 : Form
{
private Clock clock;
public Form1()
{
InitializeComponent();
clock = new Clock(digital);
}
private void start_Click(object sender, System.EventArgs e)
{ clock.Start(); }
private void stop_Click(object sender, System.EventArgs e)
{ clock.Stop(); }
} // end class Form1
}
Here I have the Form1.designer part
// ** Form1 Designer ***
Namespace Delegates
{
partial class Form1
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
protected override void Dispose(bool disposing)
{
if (disposing && (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.stop = new System.Windows.Forms.Button();
this.start = new System.Windows.Forms.Button();
this.digital = new System.Windows.Forms.TextBox();
this.SuspendLayout();
//
// stop
//
this.stop.Location = new System.Drawing.Point(144, 67);
this.stop.Name = "stop";
this.stop.Size = new System.Drawing.Size(48, 23);
this.stop.TabIndex = 5;
this.stop.Text = "Stop";
this.stop.Click += new System.EventHandler(this.stop_Click);
//
// start
//
this.start.Location = new System.Drawing.Point(72, 67);
this.start.Name = "start";
this.start.Size = new System.Drawing.Size(56, 23);
this.start.TabIndex = 4;
this.start.Text = "Start";
this.start.Click += new System.EventHandler(this.start_Click);
//
// digital
//
this.digital.Enabled = false;
this.digital.Font = new System.Drawing.Font("Courier New",
20.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point,
((byte)(0)));
this.digital.Location = new System.Drawing.Point(56, 19);
this.digital.Name = "digital";
this.digital.Size = new System.Drawing.Size(152, 38);
this.digital.TabIndex = 3;
this.digital.Text = "04:11:34";
this.digital.TextAlign =
System.Windows.Forms.HorizontalAlignment.Center;
//
// Form1
//
this.ClientSize = new System.Drawing.Size(264, 109);
this.Controls.Add(this.stop);
this.Controls.Add(this.start);
this.Controls.Add(this.digital);
this.Name = "Form1";
this.Text = "Digital Clock";
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.Button stop;
private System.Windows.Forms.Button start;
private System.Windows.Forms.TextBox digital;
}
}
The third class is the Clock class
// ** Clock ***
using System.Windows.Forms;
namespace Delegates
{
class Clock
{
private Ticker pulsed = new Ticker();
private TextBox display;
public Clock(TextBox display)
{ this.display = display; }
public void Start()
{ pulsed.tick += new Ticker.Tick(RefreshTime); }
public void Stop()
{ pulsed.tick -= new Ticker.Tick(RefreshTime); }
private void RefreshTime(int hh, int mm, int ss)
{ display.Text = string.Format("{02}:{12}:{22}", hh, mm,
); }
}
//Start class Ticker
Namespace Delegates
{
using System.Timers;
class Ticker
{
public delegate void Tick(int hh, int mm, int ss);
public event Tick tick;
private Timer ticking = new Timer();
public Ticker()
{
ticking.Elapsed += new ElapsedEventHandler(OnTimedElapsed);
ticking.Interval = 1000;
ticking.Enabled = true;
}
private void Notify(int hours, int minutes, int seconds)
{ if (tick != null) tick(hours, minutes, seconds); }
private void OnTimedElapsed(object source, ElapsedEventArgs args)
{
int hh = args.SignalTime.Hour;
int mm = args.SignalTime.Minute;
int ss = args.SignalTime.Second;
Notify(hh, mm, ss); // call notify
}
}
} // end class Ticker