0

Recently I started learning C# by writing a simple application that watches directory and updates form based on lines written to file in that directory. At some point I was stuck with common InvalidOperationException while trying to update form element from FileWatcher event.

I've searched stackoverflow, and it seems that I should use Task-based Asynchronous Pattern (TAP) in such situations, but I can't figure out which method I should flag as async, and which to start as a Task. There are many related questions on stackoverflow, but none I've found cover all 3 aspects of my application:

  • Using FileWatcher
  • Updating Form element
  • Using TAP

So, what is the best practice to update Form elements from events, fired by FileWatcher if I want to use Task-based Asynchronous Pattern? Or should I use another pattern / another application structure?

Here is a simplified example of my app:

// Form
public partial class FormMain : Form, IDisplayInterface
{
    private CoreClass coreClass;

    public void SetSomeVaue(string value)
    {
        label.Text = value;
    }

    public FormMain()
    {
        coreClass = new CoreClass();
        coreClass.StartFileWatcher();
    }

    private void FormMain_Shown(object sender, EventArgs e)
    {
        coreClass.DisplayInterface = this;
    }
}

// Interface
interface IDisplayInterface
{
    void SetSomeVaue(string value);
}

// CoreClass
class CoreClass
{
    public IDisplayInterface DisplayInterface;

    public void StartFileWatcher()
    {
        FileSystemWatcher watcher = new FileSystemWatcher("C:\Some\Folder")
        {
            NotifyFilter = NotifyFilters.Size
        };
        watcher.Changed += new FileSystemEventHandler(FileUpdated);
        watcher.EnableRaisingEvents = true;
    }

    private void FileUpdated(object source, FileSystemEventArgs e)
    {
        ParseFile(Path.Combine("C:\Some\Folder", e.Name));
    }

    private void ParseFile(string File)
    {
        // foreach (var line in newFileLines)
            ParseNewRecord(line);
    }

    private void ParseNewRecord(string line)
    {
        if (someCondition && DisplayInterface != null)
        {
            // This triggers Exception for accessing FormMain from a thread that did not create it
            DisplayInterface.SetSomeValue(someValue);
        }
    }

}

UPDATE 21.07:

It looks that I got the wrong idea about using TAP everywhere, so I finally did it by invoking a delegate containing my SetSomeVaue method and it works correctly (I hope that is a correct decision).

Thanks for response!

xndr_78
  • 1
  • 2
  • 1
    Does [this](https://stackoverflow.com/questions/13945225/cross-thread-operation-not-valid-in-windows-forms) help ? – Zein Makki Jul 18 '17 at 12:22
  • @user3185569 I havent tried invoking a delegate yet, because it looks like I should use TAP in .NET 4.5+ according to [this](http://stackoverflow.com/a/18033198/1985167) answer – xndr_78 Jul 18 '17 at 12:36
  • I don't think you can use TPL with `FileSystemWatcher` – Zein Makki Jul 18 '17 at 13:31
  • 1
    What dose TAP have to do with anything FileSystemWatcher is EAP. And the two are not mutually exclusive. You should use EAP for FileWatcher because is better thing to use. You could trasforme any event to a task but in this case it's should not be done.And Invoke and InvokeAsync has nothing to do with TAP of EPL. – Filip Cordas Jul 18 '17 at 13:45
  • Here's an example on how to wrap a `FileSystemWatcher` in a Task: https://stackoverflow.com/questions/17408499/async-wait-for-file-to-be-created. TBH, _like others have said_ — I think it's better to stick with `FileSystemWatcher` default pattern (EAP) on this one. – IronGeek Jul 18 '17 at 15:23
  • Also you code has a memory leek. And you should not do it this way. – Filip Cordas Jul 18 '17 at 15:53
  • @FilipCordas thanks, I'll read about EAP. Could you be more specific about memory leak? – xndr_78 Jul 18 '17 at 17:16
  • It's not clear at all what you even mean. It's like you just heard some vague statement about TPL being all the rage these days, and so you want to apply that to the `FileSystemWatcher` scenario. TPL is suitable for **task**-oriented scenarios, where you want some work done asynchronously and need the result returned later. This could be applied to FSW if you have a scenario where you're running FSW just long enough to observe a single file-system event and you want to wait for that asynchronously. – Peter Duniho Jul 18 '17 at 22:35
  • 1
    But the usual FSW scenarios involve on-going monitoring; this is more queue-based than task-based. Maybe `BlockingCollection` with a dedicated thread to consume the data would be more appropriate in your scenario. Hard to say...the question is very broad. – Peter Duniho Jul 18 '17 at 22:35
  • In regards to the memory leek you Form and CoreClass have references to one another(Not really that good thing to do). The event handler is using the DisplayInterface. Now when you close the form the event handler will continue to exist and will just continue to run the EventHandler. you need to dispose or unsubscribe from the FileSystemWatcher. – Filip Cordas Jul 19 '17 at 08:54
  • @PeterDuniho You're correct, I just read everybody should use TPL, but didn't understand the context. I'm really new to C# and all this asynchronous code flow is a bit confusing to me after 8 years of backend web-development, but now I'm starting to get it, big thanks for clarification – xndr_78 Jul 21 '17 at 14:01
  • @FilipCordas but if it is the main form of my application and when you close the form, the application exits - wont garbage collector take care of everything, inc. FileSystemWatcher? – xndr_78 Jul 21 '17 at 14:04
  • @xndr_78 That is true if you kill the process you won't have a memory leek But this doesn't mean that there isn't one if you open a different form and then close the original the memory leek will be there. – Filip Cordas Jul 21 '17 at 15:23
  • @xndr_78 also what can happen is have a dangling thread unclosed because of this structure. It's always best to not let it happen and clean up after your self. Usually a Messenger service is used to deal with this so you don't forget to clean something by accident. – Filip Cordas Jul 21 '17 at 15:31

0 Answers0