Create a Synchronizing Object






4.75/5 (4 votes)
How to create a synchronizing object using the ISynchronizeInvoke interface like in the FileSystemWatcher.
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: https://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;
//Event that handles incomming files...
public event EventHandler FileListDone;
//Event that handles when list is done...
private Thread BackGroundThread; //local background worker.
private ISynchronizeInvoke synchronizingObject;
//Contains the object to Sync up against.
[Browsable(false), DefaultValue((string)null)]
public ISynchronizeInvoke SynchronizingObject
//Property to get or set the object to Sync up against.
{
get { return this.synchronizingObject; }
set { this.synchronizingObject = value; }
}
protected void OnIncommingFile(FileEventArgs e)
{
if (this.IncommingFile != null)
//if the IncommingFile event is not null.
//(meaning that an subscriber to the event is present...)
{
//SynchronizingObject is not null and the Synchronizing
//Object Requires and invokation...
if ((this.SynchronizingObject != null) &&
this.SynchronizingObject.InvokeRequired)
this.SynchronizingObject.BeginInvoke(IncommingFile,
new object[] { this, e });
//Get the Synchronizing Object to invoke the event...
else
IncommingFile(this, e); //Fire the event
}
}
protected void OnFileListDone()
{
if (this.FileListDone != null)
//if the FileListDone event is not null.
//(meaning that an subscriber to the event is present...)
{
//SynchronizingObject is not null and
//the Synchronizing Object Requires and invokation...
if ((this.SynchronizingObject != null) &&
this.SynchronizingObject.InvokeRequired)
this.SynchronizingObject.BeginInvoke(FileListDone,
new object[] { this, null });
//Get the Synchronizing Object to invoke the event...
else
FileListDone(this, null); //Fire the event
}
}
public void ListFilesFrom(string path)
{
//create and BackgroundWorker thread, with parameters...
BackGroundThread =
new Thread(new ParameterizedThreadStart(getFilesInNewThread));
BackGroundThread.Start(path); //Start the Thead with the parameter...
}
private void getFilesInNewThread(object path)
{
//get the parameter which is the path
//to where the list should list files from.
string folderpath = path.ToString();
if (Directory.Exists(folderpath))
//if the folder exists...
{
//Create an new instance of the DirectoryInfo class,
//which can get an array if FileSystemInfo objects.
DirectoryInfo di = new DirectoryInfo(folderpath);
//Get the FileSystemInfo objects...
FileSystemInfo[] files = di.GetFileSystemInfos();
int total = files.Length; //Get total cound of files to send to GUI.
for (int i = 0; i < total; i++) // loop through the array..
OnIncommingFile(new FileEventArgs(i, total, files[i]));
//Send one file at the time through the event.
//(NOTE: normaly this would not be the case, as one would send
// the hole array in one piece. but for demo reason this is so...)
}
OnFileListDone(); //Fire the Event saying the loop is done...
}
public void StopFilelistEnumeration()
{
if (BackGroundThread != null && BackGroundThread.IsAlive)
//if the backgroundworker thread is not null and is running then...
BackGroundThread.Abort(); //Abort/kill the thread.
}
}
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.