Introduction
Ever needed a SynchronizingObject
for multithreaded applications?
Let's say you want to list files like this demo does, and you get the files from a working thread other than the one the UI is running on, then you would get cross-thread exceptions, which would lead you into writing extra code, just for the hell of it, right???
If you know the FileSystemWatcher
class, you may have noticed the SynchronizingObject
which you can assign your UI form to and you would get around the cross-thread exception.
Well, the SynchronizingObject
is of type ISynchronizeInvoke
, which all System.Windows.Forms.Control
derive from. Which means, all controls can be added to this property. Nice, right?
Background
Had a friend asking about cross-thread exceptions.
Using the code
This demo does not implement the ISynchronizeInvoke
interface, it will use it as a property on a custom class.
If you want to learn more about implementing the ISynchronizeInvoke
interface, I recommend this nice CP article: http://www.codeproject.com/KB/cs/delegatequeue.aspx.
OK, back to my article, hopefully ;o)
FileEventArgs class
It's pretty simple. It contains information about the total count of files that will be returned by my custom list class, the current position of the file in the list, and the file information of the current file.
public class FileEventArgs : EventArgs
{
int _current;
int _total;
FileSystemInfo _file;
public int Current
{
get { return _current; }
}
public int Total
{
get { return _total; }
}
public FileSystemInfo File
{
get { return _file; }
}
internal FileEventArgs(int current, int total, FileSystemInfo file)
{
_current = current;
_total = total;
_file = file;
}
}
FileEventHandler delegate
It will be used for the events on my custom list class.
public delegate void FileEventHandler(object sender, FileEventArgs e);
FileLister class
I've added the comments in the code ...
public class FileLister
{
public event FileEventHandler IncommingFile;
public event EventHandler FileListDone;
private Thread BackGroundThread;
private ISynchronizeInvoke synchronizingObject;
[Browsable(false), DefaultValue((string)null)]
public ISynchronizeInvoke SynchronizingObject
{
get { return this.synchronizingObject; }
set { this.synchronizingObject = value; }
}
protected void OnIncommingFile(FileEventArgs e)
{
if (this.IncommingFile != null)
{
if ((this.SynchronizingObject != null) &&
this.SynchronizingObject.InvokeRequired)
this.SynchronizingObject.BeginInvoke(IncommingFile,
new object[] { this, e });
else
IncommingFile(this, e);
}
}
protected void OnFileListDone()
{
if (this.FileListDone != null)
{
if ((this.SynchronizingObject != null) &&
this.SynchronizingObject.InvokeRequired)
this.SynchronizingObject.BeginInvoke(FileListDone,
new object[] { this, null });
else
FileListDone(this, null);
}
}
public void ListFilesFrom(string path)
{
BackGroundThread =
new Thread(new ParameterizedThreadStart(getFilesInNewThread));
BackGroundThread.Start(path);
}
private void getFilesInNewThread(object path)
{
string folderpath = path.ToString();
if (Directory.Exists(folderpath))
{
DirectoryInfo di = new DirectoryInfo(folderpath);
FileSystemInfo[] files = di.GetFileSystemInfos();
int total = files.Length;
for (int i = 0; i < total; i++)
OnIncommingFile(new FileEventArgs(i, total, files[i]));
}
OnFileListDone();
}
public void StopFilelistEnumeration()
{
if (BackGroundThread != null && BackGroundThread.IsAlive)
BackGroundThread.Abort();
}
}
Please see the demo!!!
For more information on how to use the class and its SynchronizingObject
, please see the demo.
Points of interest
From this small sample, my friend was able to create more thread safe classes.
Hope you can use it...
History
- 25 Aug. 2009: Article posted.