rickywh Posted February 14, 2009 Posted February 14, 2009 I'm trying to watch the directory where my application .exe runs from. Watching for directory changes, filename changes, etc etc I'm using the FileSystemWatcher class and set the Path property to the right directory just fine. When I ran my original application, i used just a regular method for handling the Changed event and tried updating my textBox1.Text property to show the Name property however I was receiving the cross thread exception that shows that your not supposed to do it that way unless you want possible instability.... So I read the MSDN article about how to make thread-safe calls to update GUI controls. There are two known methods for doing so as shown in the MSDN article. http://msdn.microsoft.com/en-us/library/ms171728.aspx 1. Invoke 2. BackgroundWorker After reading the Invoke example, I get lost at the part where it says this.... SetTextCallback d = new SetTextCallback(SetText); this.Invoke(d, new object[] { text }); As shown above, it's implying we know what the SetTextCallback(SetText) method is supposed to do and how it's implemented but since i'm new, i have no idea what this is about.... Instead, I chose to try the BackgroundWorker example instead so after implementing the BackgroundWorker method, I end up receiving the very same cross thread exception as originally when I tried to do it just by trying to set the Text property in the Changed event handler. So i've implemented the BackgroundWorker method for making the aparently thread-safe update to my TextBoxes Text propertly as shown on the MSDN site, but I still receive the cross thread exception error! using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.IO; using System.Net; using System.Linq; using System.Text; using System.Windows.Forms; using System.Text.RegularExpressions; namespace FileSystemWatcherTest1 { public partial class Form1 : Form { BackgroundWorker myWorker1 = new BackgroundWorker(); FileSystemWatcher myWatcher = new FileSystemWatcher(); Regex r = new Regex(@".*\..*"); public Form1() { InitializeComponent(); } private void button1_Click(object sender, EventArgs e) { } private void Form1_Load(object sender, EventArgs e) { // Set methods for Background worker's DoWork and RunWorkerCompleted events. myWorker1.DoWork += new DoWorkEventHandler(myWorker1_DoWork); myWorker1.RunWorkerCompleted += new RunWorkerCompletedEventHandler(myWorker1_RunWorkerCompleted); // Get this applications path. string path = Application.ExecutablePath.ToString(); string[] results = path.Split(new char[] { '\\' }, StringSplitOptions.None); int num = results.Length - 1; results.SetValue("", num); string finalPath = String.Join("\\", results); // set the Path property myWatcher.Path = finalPath; myWatcher.IncludeSubdirectories = true; myWatcher.NotifyFilter = NotifyFilters.CreationTime | NotifyFilters.DirectoryName | NotifyFilters.LastWrite | NotifyFilters.Attributes | NotifyFilters.LastAccess | NotifyFilters.Size; // add even handlers myWatcher.Changed += new FileSystemEventHandler(myWatcher_Changed); // Enable raising events myWatcher.EnableRaisingEvents = true; //textBox1.Text = "Path has been set on the FileSystemWatcher"; } void myWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) { // update the UI control here, still gets a cross thread exception... this.textBox1.Text += (string)e.Result + Environment.NewLine; } void myWorker1_DoWork(object sender, DoWorkEventArgs e) { BackgroundWorker bgworker = sender as BackgroundWorker; e.Result = (string)e.Argument; } void myWatcher_Changed(object sender, FileSystemEventArgs e) { myWorker1.RunWorkerAsync(e.Name); } } } Any help, Much appreciated, Quote
Administrators PlausiblyDamp Posted February 14, 2009 Administrators Posted February 14, 2009 Are you doing anything else involving threads? I can't see why either your original code or the above background worker code would throw a cross thread exception. Quote Posting Guidelines FAQ Post Formatting Intellectuals solve problems; geniuses prevent them. -- Albert Einstein
rickywh Posted February 14, 2009 Author Posted February 14, 2009 Thanks for your reply, My code definitely produces an exception as shown in my screen shot below. http://img19.imageshack.us/img19/4742/invalidexception1hx4.jpg Also, I uploaded my whole project in case you want to load it up to see the rest of the code... http://www.megaupload.com/?d=1474S0I4 Quote
Administrators PlausiblyDamp Posted February 14, 2009 Administrators Posted February 14, 2009 try using System; using System.ComponentModel; using System.IO; using System.Text.RegularExpressions; using System.Windows.Forms; namespace FileSystemWatcherTest1 { public partial class Form1 : Form { private readonly FileSystemWatcher myWatcher = new FileSystemWatcher(); private BackgroundWorker myWorker1 = new BackgroundWorker(); private Regex r = new Regex(@".*\..*"); public Form1() { InitializeComponent(); } private void button1_Click(object sender, EventArgs e) {} private void Form1_Load(object sender, EventArgs e) { // Get this applications path. string path = Application.ExecutablePath; string[] results = path.Split(new[]{'\\'}, StringSplitOptions.None); int num = results.Length - 1; results.SetValue("", num); string finalPath = String.Join("\\", results); // set the Path property myWatcher.Path = finalPath; myWatcher.SynchronizingObject = this; myWatcher.IncludeSubdirectories = true; myWatcher.NotifyFilter = NotifyFilters.CreationTime | NotifyFilters.DirectoryName | NotifyFilters.LastWrite | NotifyFilters.Attributes | NotifyFilters.LastAccess | NotifyFilters.Size; // add even handlers myWatcher.Changed += myWatcher_Changed; // Enable raising events myWatcher.EnableRaisingEvents = true; //textBox1.Text = "Path has been set on the FileSystemWatcher"; } private void myWatcher_Changed(object sender, FileSystemEventArgs e) { MakeChanges(e.Name); } private void MakeChanges(string result) { textBox1.Text += result + Environment.NewLine; } } } The key is the line myWatcher.SynchronizingObject = this; as this forces the event to be raised on the UI thread.Due to the fact this class may be used in several different scenarios forcing this single threaded event behaviour would be a major performance hit when direct UI interaction isn't required - setting this property http://msdn.microsoft.com/en-us/library/system.io.filesystemwatcher.synchronizingobject.aspx gives the full details. Quote Posting Guidelines FAQ Post Formatting Intellectuals solve problems; geniuses prevent them. -- Albert Einstein
rickywh Posted February 14, 2009 Author Posted February 14, 2009 Hey PlausiblyDamp, thanks! Yes that worked, I would have never have otherwise found this out. Yes it solved my problem, may I ask how you find the answer to this one?? Quote
Administrators PlausiblyDamp Posted February 19, 2009 Administrators Posted February 19, 2009 A bit of google and the problem seemed to ring a bell with something I had problems with in the past. Quote Posting Guidelines FAQ Post Formatting Intellectuals solve problems; geniuses prevent them. -- Albert Einstein
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.