0

This is mt first time trying to write a not web based program, and my first time writing anything in C#.

I need a program that monitors folders, but I can't get it to work. I have used the example from this post Using FileSystemWatcher with multiple files but is trying to make it a form.

My current problem comes in the ProcessQueue function where fileList apparently is defined in another thread. Whenever a file is actually submitted to the watched folder I get an error that using fileList is a cross thread call

Can anyone explain this error to me, and how to fix it?

namespace matasWatch
{
    public partial class Form1 : Form
    {
        private int n = 1;
        private bool isWatching = false;
        private List<string> filePaths;
        private System.Timers.Timer processTimer;
        private string watchedPath;
        private FileSystemWatcher watcher;

        public Form1()
        {
            filePaths = new List<string>();
            watchedPath = "C:\\Users\\username\\Desktop\\test";
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            if (!isWatching)
            {
                button1.Text = "Stop";
                isWatching = true;
                watcher = new FileSystemWatcher();
                watcher.Filter = "*.*";
                watcher.Created += Watcher_FileCreated;
                watcher.Error += Watcher_Error;
                watcher.Path = watchedPath;
                watcher.IncludeSubdirectories = true;
                watcher.EnableRaisingEvents = true;
            }
            else {
                button1.Text = "Watch";
                isWatching = false;

                watcher.EnableRaisingEvents = false;
                watcher.Dispose();
                watcher = null;
            }
        }

        private void Watcher_Error(object sender, ErrorEventArgs e)
        {
            // Watcher crashed. Re-init.
            isWatching = false;
            button1_Click(sender, e);
        }

        private void Watcher_FileCreated(object sender, FileSystemEventArgs e)
        {
            filePaths.Add(e.FullPath);

            if (processTimer == null)
            {
                // First file, start timer.
                processTimer = new System.Timers.Timer(2000);
                processTimer.Elapsed += ProcessQueue;
                processTimer.Start();
            }
            else{
                // Subsequent file, reset timer.
                processTimer.Stop();
                processTimer.Start();
            }
        }

        private void ProcessQueue(object sender, ElapsedEventArgs args)
        {
            try
            {
                fileList.BeginUpdate();
                foreach (string filePath in filePaths)
                {
                    fileList.Items.Add("Blaa");
                }
                fileList.EndUpdate();
                filePaths.Clear();
            }
            finally
            {
                if (processTimer != null)
                {
                    processTimer.Stop();
                    processTimer.Dispose();
                    processTimer = null;
                }
            }
        }
    }
}
Community
  • 1
  • 1
Zlug
  • 373
  • 2
  • 15
  • You forgot to tell us what the error is. You diagnosed the cause as "fileList apparently is defined in another thread", but you didn't tell us what error you're trying to diagnose the cause of. What goes wrong exactly? – David Schwartz Oct 25 '12 at 09:38
  • You probably need to use `Form.Invoke` to manipulate UI elements in another thread. – Alvin Wong Oct 25 '12 at 09:38
  • Looks like your BeginUpdate is Asynchronous and may be you are trying to update something on the main form from that method.You cannot do that – Prabhu Murthy Oct 25 '12 at 09:39
  • can you tell us what the error is? Although I'm guessing that it's probably because you're trying to update the UI from the non-UI thread - here is a good article about this [WinForms UI Thread Invokes: An In-Depth Review of Invoke/BeginInvoke/InvokeRequred by Justin Rogers](http://weblogs.asp.net/justin_rogers/pages/126345.aspx) – Andras Zoltan Oct 25 '12 at 09:42
  • 2
    @Zlug, bonus answer: delete the blank line before last `}` and after `isWatching = false;` – Tomas Ramirez Sarduy Oct 25 '12 at 09:43

2 Answers2

1

I assume that fileList is a windows forms control. The ProcessQueue method is called from a timer thread which is by default a background thread. The fileList control resides in the UI thread. You need to use the Invoke() method of the form passing it in a delegate the updates the fileList control.

    Invoke(new Action(() => 
    { 
        fileList.BeginUpdate();
        foreach (string filePath in filePaths)
        {
            fileList.Items.Add("Blaa");
        }
        fileList.EndUpdate();
        filePaths.Clear();    
    }));
Daniel
  • 64
  • 1
0

Try using System.Windows.Forms.Timer instead of System.Timers.Timer so the timer tick event is executed on the UI thread.

See here for more details.

Henrik
  • 23,186
  • 6
  • 42
  • 92