Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / desktop / WinForms

Create a Synchronizing Object

4.75/5 (4 votes)
25 Aug 2009CPOL1 min read 43.2K   682  
How to create a synchronizing object using the ISynchronizeInvoke interface like in the FileSystemWatcher.

Image 1

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.

C#
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.

C#
public delegate void FileEventHandler(object sender, FileEventArgs e); 

FileLister class

I've added the comments in the code ...

C#
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.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)