Revision: 39446
Initial Code
Initial URL
Initial Description
Initial Title
Initial Tags
Initial Language
at January 18, 2011 00:45 by kyrathaba
Initial Code
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; _openFileDelegate = new DelegateOpenFile(this.OpenFile); backgroundWorker1 = new BackgroundWorker(); backgroundWorker1.RunWorkerCompleted += new RunWorkerCompletedEventHandler(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) { OpenFileDialog openDlg = new OpenFileDialog(); 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.BeginInvoke(_openFileDelegate, new Object[] { s }); 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 = new Thread(new ThreadStart(this.ThreadProcUnsafe)); 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 = new Thread(new ThreadStart(this.ThreadProcSafe)); 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) { SetTextCallback d = new SetTextCallback(SetText); this.Invoke(d, new object[] { text }); } 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."; } } }
Initial URL
Initial Description
demonstrates safe versus unsafe ways to make cross-thread calls
Initial Title
Safe vs. UnSafe cross-thread call
Initial Tags
Initial Language
C#