/ Published in: C#
demonstrates safe versus unsafe ways to make cross-thread calls
Expand |
Embed | Plain Text
Copy this code and paste it in your HTML
using System; using System.Windows.Forms; using System.Diagnostics; using System.ComponentModel; using System.Threading; using System.IO; namespace CrossThreadCallsToAControl { public partial class Form1 : Form { // This delegate enables asynchronous calls for setting // the text property on a TextBox control. delegate void SetTextCallback(string text); // This thread is used to demonstrate both thread-safe and // unsafe ways to call a Windows Forms control. private Thread demoThread = null; // This BackgroundWorker is used to demonstrate the // preferred way of performing asynchronous operations. private BackgroundWorker backgroundWorker1; private delegate void DelegateOpenFile(String s); DelegateOpenFile _openFileDelegate; public const string appTitle = "My App Title"; public Form1() { InitializeComponent(); this.StartPosition = FormStartPosition.CenterScreen; this.Text = appTitle; this.AllowDrop = true; backgroundWorker1.RunWorkerCompleted += } private void Form1_Load(object sender, EventArgs e) { } private void Form1_MouseClick(object sender, MouseEventArgs e) { switch (e.Button) { case MouseButtons.Left: break; case MouseButtons.Right: string path = Path.GetDirectoryName(Application.ExecutablePath); System.Diagnostics.Process.Start("explorer.exe", path); break; default: break; } } private void Form1_KeyDown(object sender, KeyEventArgs e) { if (e.KeyCode == Keys.Escape) { Application.Exit(); } } private void openToolStripMenuItem_Click(object sender, EventArgs e) { openDlg.Filter = "Any File (*.*)|*.*"; openDlg.FileName = ""; openDlg.CheckFileExists = true; openDlg.CheckPathExists = true; if (openDlg.ShowDialog() != DialogResult.OK) return; OpenFile(openDlg.FileName); } private void OpenFile(string sFile) { //insert appropriate file-opening code here... MessageBox.Show("\"" + sFile + "\" will be opened."); } private void Form1_DragEnter(object sender, DragEventArgs e) { if (e.Data.GetDataPresent(DataFormats.FileDrop)) e.Effect = DragDropEffects.Copy; else e.Effect = DragDropEffects.None; } private void Form1_DragDrop(object sender, DragEventArgs e) { try { Array a = (Array)e.Data.GetData(DataFormats.FileDrop); if (a != null) { // Extract string from first array element // (ignore all files except first if number of files are dropped). string s = a.GetValue(0).ToString(); // Call OpenFile asynchronously. // Explorer instance from which file is dropped is not responding // the entire time that the DragDrop handler is active, so we need to return // immidiately (especially if OpenFile shows MessageBox). this.Activate(); // in the case Explorer overlaps this form } } catch (Exception ex) { Trace.WriteLine("Error in DragDrop function: " + ex.Message); // don't show MessageBox here - Explorer is waiting ! } } private void setTextUnsafeBtn_Click(object sender, EventArgs e) { this.demoThread = this.demoThread.Start(); } // This method is executed on the worker thread and makes // an unsafe call on the TextBox control. private void ThreadProcUnsafe() { this.textBox1.Text = "This text was set unsafely."; } private void setTextSafeBtn_Click(object sender, EventArgs e) { this.demoThread = this.demoThread.Start(); } // This method is executed on the worker thread and makes // a thread-safe call on the TextBox control. private void ThreadProcSafe() { this.SetText("This text was set safely."); } // This method demonstrates a pattern for making thread-safe // calls on a Windows Forms control. // // If the calling thread is different from the thread that // created the TextBox control, this method creates a // SetTextCallback and calls itself asynchronously using the // Invoke method. // // If the calling thread is the same as the thread that created // the TextBox control, the Text property is set directly. private void SetText(string text) { // InvokeRequired required compares the thread ID of the // calling thread to the thread ID of the creating thread. // If these threads are different, it returns true. if (this.textBox1.InvokeRequired) { } else { this.textBox1.Text = text; } } private void setTextBackgroundWorkerBtn_Click(object sender, EventArgs e) { this.backgroundWorker1.RunWorkerAsync(); } // This event handler sets the Text property of the TextBox // control. It is called on the thread that created the // TextBox control, so the call is thread-safe. // // BackgroundWorker is the preferred way to perform asynchronous // operations. private void backgroundWorker1_RunWorkerCompleted( object sender, RunWorkerCompletedEventArgs e) { this.textBox1.Text = "This text was set safely by BackgroundWorker."; } } }