0

I have a filewatcher that is watching a directory for file changes. When it happens, each file is queued in a Queue managed by a FileProcessor class (with Threads). I would like to update in a label which in the Form1 the number of files in the Q (everytime that number is updated) i tried several things including :

class FileProcessor : IDisposable
{
   private static Form1 frm;

and the call later in the class :

frm.Invoke((MethodInvoker)delegate { frm.button4.Text = Qcounte(); });

I have a System.NullReferenceException because i do not know how to declare Form1 in frm :(

Here is the Main form with the function to update the label : SetQ(string s)

public delegate void ddisplayQ(string q);
public partial class Form1 : Form
{
    public static ddisplayQ deldisplayQ;
public Form1()
    {
        InitializeComponent();
        deldisplayQ = new ddisplayQ(this.setQ);
    }
private void setQ(string s)
    {
        button4.Text = s;
    }

on the FileProcessor class, here is how i'm calling the update of the label :

Form1.deldisplayQ.Invoke(Qcounte());

public string Qcounte()
    {
        return Convert.ToString(fileNamesQueue.Count);
    }

            Form1.deldisplayQ.Invoke(Qcounte());

Here is the whole class :

 class FileProcessor : IDisposable
{
    private EventWaitHandle eventWaitHandle = new AutoResetEvent(false);
    private Thread worker;
    private readonly object locker = new object();
    private Queue<string> fileNamesQueue = new Queue<string>();
    public static Form1 frm ;
     public FileProcessor()
    {
        worker = new Thread(Work);
        worker.Start();
    }

    public void EnqueueFileName(string FileName)
    {
        lock (locker) fileNamesQueue.Enqueue(FileName);
        eventWaitHandle.Set();
    }
    private void Work()
    {
        while (true)
        {
            string fileName = null;
            lock (locker)
                if (fileNamesQueue.Count > 0)
                {
                    if (fileName == null) return;
                }
            if (fileName != null)
            {
                ProcessFile(fileName);
            }
            else
            {
                eventWaitHandle.WaitOne();
            }
        }
    }
    private void ProcessFile(string FileName)
    {
        Globals.getTags(FileName);
        Globals.ecritDb(FileName);
    }
    public string Qcounte()
    {
        return Convert.ToString(fileNamesQueue.Count);
    }
    #region IDisposable Members

    public void Dispose()
    {
        EnqueueFileName(null);
        worker.Join();
        eventWaitHandle.Close();
    }

    #endregion
}

My question is : Where to trigger the enqueue and the dequeue in the FileProcessor class so that i can see the increase and the decrease of the file processing in my main form ? thanks in advance

1 Answers1

0

The code doesn't look complete to me but here are some things you should do:

  1. From the FileProcessor, you have a reference of the Form. My assumption is that there will only be 1 instance of the form correct? So add public static Form1 Instance { get; set; } to the Form1 class. Set it in the constructor of the Form.

    public partial class Form1 : Form
    {
       public static Form1 Instance { get; set; }
    
       public Form1()
       {
         InitializeComponent();
         Instance = this;
       }
    
       public void UpdateText(string text)
       {
         BeginInvoke(  new Action( () =>
         {
           button4.Text = text;
         }));
        }
    
  2. So back to the FileProcessor, remove the instance variable of Form. To invoke the UI update of the textbox on the Form simply add the methods on the Form class as instance methods. The only difference is to use BeginInvoke() This is important because the FileProcessor is running on a different thread and will not be able to change any UI controls.

    private void ProcessFile(string FileName)
    {
       Globals.getTags(FileName);
       Globals.ecritDb(FileName);
    
       //update UI
       Form1.Instance.UpdateText("hello");
    }
    

How to use BeginInvoke C#

Of course we could use interfaces or abstractions here instead of direct access to the Form, but sometimes simple is adequate.

T McKeown
  • 12,971
  • 1
  • 25
  • 32
  • wow thanks ! i have an exception when i past the public void UpdateText(string text) : Cannot convert lambda expression to type 'Delegate' because it is not a delegate type – Sebastien Chemouny Mar 06 '20 at 19:15
  • I modified the UpdateText method, copy it and try again. – T McKeown Mar 06 '20 at 19:20
  • yeah i figured that out, reading the link you provided ... Thanks, the delegate works very well (thanks), the Queue management, not (or it's too fast). I'll investigate if there is events for queue. – Sebastien Chemouny Mar 06 '20 at 19:23