Posted By

kyrathaba on 01/18/11


Tagged

safe Threads calls unsafe cross-thread invocations


Versions (?)

Safe vs. UnSafe cross-thread call


 / Published in: C#
 

demonstrates safe versus unsafe ways to make cross-thread calls

  1. using System;
  2. using System.Windows.Forms;
  3. using System.Diagnostics;
  4. using System.ComponentModel;
  5. using System.Threading;
  6. using System.IO;
  7.  
  8. namespace CrossThreadCallsToAControl {
  9. public partial class Form1 : Form {
  10.  
  11. // This delegate enables asynchronous calls for setting
  12. // the text property on a TextBox control.
  13. delegate void SetTextCallback(string text);
  14.  
  15. // This thread is used to demonstrate both thread-safe and
  16. // unsafe ways to call a Windows Forms control.
  17. private Thread demoThread = null;
  18.  
  19. // This BackgroundWorker is used to demonstrate the
  20. // preferred way of performing asynchronous operations.
  21. private BackgroundWorker backgroundWorker1;
  22.  
  23. private delegate void DelegateOpenFile(String s);
  24. DelegateOpenFile _openFileDelegate;
  25.  
  26. public const string appTitle = "My App Title";
  27.  
  28. public Form1() {
  29. InitializeComponent();
  30. this.StartPosition = FormStartPosition.CenterScreen;
  31. this.Text = appTitle;
  32. this.AllowDrop = true;
  33. _openFileDelegate = new DelegateOpenFile(this.OpenFile);
  34. backgroundWorker1 = new BackgroundWorker();
  35. backgroundWorker1.RunWorkerCompleted +=
  36. new RunWorkerCompletedEventHandler(backgroundWorker1_RunWorkerCompleted);
  37. }
  38.  
  39. private void Form1_Load(object sender, EventArgs e) {
  40. }
  41.  
  42. private void Form1_MouseClick(object sender, MouseEventArgs e) {
  43. switch (e.Button) {
  44. case MouseButtons.Left:
  45. break;
  46. case MouseButtons.Right:
  47. string path = Path.GetDirectoryName(Application.ExecutablePath);
  48. System.Diagnostics.Process.Start("explorer.exe", path);
  49. break;
  50. default:
  51. break;
  52. }
  53. }
  54.  
  55. private void Form1_KeyDown(object sender, KeyEventArgs e) {
  56. if (e.KeyCode == Keys.Escape) { Application.Exit(); }
  57. }
  58.  
  59. private void openToolStripMenuItem_Click(object sender, EventArgs e) {
  60. OpenFileDialog openDlg = new OpenFileDialog();
  61. openDlg.Filter = "Any File (*.*)|*.*";
  62.  
  63. openDlg.FileName = "";
  64. openDlg.CheckFileExists = true;
  65. openDlg.CheckPathExists = true;
  66.  
  67. if (openDlg.ShowDialog() != DialogResult.OK)
  68. return;
  69.  
  70. OpenFile(openDlg.FileName);
  71. }
  72.  
  73. private void OpenFile(string sFile) {
  74. //insert appropriate file-opening code here...
  75. MessageBox.Show("\"" + sFile + "\" will be opened.");
  76. }
  77.  
  78. private void Form1_DragEnter(object sender, DragEventArgs e) {
  79. if (e.Data.GetDataPresent(DataFormats.FileDrop))
  80. e.Effect = DragDropEffects.Copy;
  81. else
  82. e.Effect = DragDropEffects.None;
  83. }
  84.  
  85. private void Form1_DragDrop(object sender, DragEventArgs e) {
  86. try {
  87. Array a = (Array)e.Data.GetData(DataFormats.FileDrop);
  88. if (a != null) {
  89. // Extract string from first array element
  90. // (ignore all files except first if number of files are dropped).
  91. string s = a.GetValue(0).ToString();
  92. // Call OpenFile asynchronously.
  93. // Explorer instance from which file is dropped is not responding
  94. // the entire time that the DragDrop handler is active, so we need to return
  95. // immidiately (especially if OpenFile shows MessageBox).
  96. this.BeginInvoke(_openFileDelegate, new Object[] { s });
  97. this.Activate(); // in the case Explorer overlaps this form
  98. }
  99. }
  100. catch (Exception ex) {
  101. Trace.WriteLine("Error in DragDrop function: " + ex.Message);
  102. // don't show MessageBox here - Explorer is waiting !
  103. }
  104. }
  105.  
  106. private void setTextUnsafeBtn_Click(object sender, EventArgs e) {
  107. this.demoThread =
  108. new Thread(new ThreadStart(this.ThreadProcUnsafe));
  109.  
  110. this.demoThread.Start();
  111. }
  112.  
  113. // This method is executed on the worker thread and makes
  114. // an unsafe call on the TextBox control.
  115. private void ThreadProcUnsafe() {
  116. this.textBox1.Text = "This text was set unsafely.";
  117. }
  118.  
  119. private void setTextSafeBtn_Click(object sender, EventArgs e) {
  120. this.demoThread =
  121. new Thread(new ThreadStart(this.ThreadProcSafe));
  122.  
  123. this.demoThread.Start();
  124. }
  125.  
  126. // This method is executed on the worker thread and makes
  127. // a thread-safe call on the TextBox control.
  128. private void ThreadProcSafe() {
  129. this.SetText("This text was set safely.");
  130. }
  131.  
  132. // This method demonstrates a pattern for making thread-safe
  133. // calls on a Windows Forms control.
  134. //
  135. // If the calling thread is different from the thread that
  136. // created the TextBox control, this method creates a
  137. // SetTextCallback and calls itself asynchronously using the
  138. // Invoke method.
  139. //
  140. // If the calling thread is the same as the thread that created
  141. // the TextBox control, the Text property is set directly.
  142.  
  143. private void SetText(string text) {
  144. // InvokeRequired required compares the thread ID of the
  145. // calling thread to the thread ID of the creating thread.
  146. // If these threads are different, it returns true.
  147. if (this.textBox1.InvokeRequired) {
  148. SetTextCallback d = new SetTextCallback(SetText);
  149. this.Invoke(d, new object[] { text });
  150. }
  151. else {
  152. this.textBox1.Text = text;
  153. }
  154. }
  155.  
  156. private void setTextBackgroundWorkerBtn_Click(object sender, EventArgs e) {
  157. this.backgroundWorker1.RunWorkerAsync();
  158. }
  159.  
  160. // This event handler sets the Text property of the TextBox
  161. // control. It is called on the thread that created the
  162. // TextBox control, so the call is thread-safe.
  163. //
  164. // BackgroundWorker is the preferred way to perform asynchronous
  165. // operations.
  166.  
  167. private void backgroundWorker1_RunWorkerCompleted(
  168. object sender,
  169. RunWorkerCompletedEventArgs e) {
  170. this.textBox1.Text =
  171. "This text was set safely by BackgroundWorker.";
  172. }
  173.  
  174.  
  175. }
  176.  
  177. }

Report this snippet  

You need to login to post a comment.