C# 如何使用基于任务的异步模式(TAP)从FileWatcher事件更新GUI

C# 如何使用基于任务的异步模式(TAP)从FileWatcher事件更新GUI,c#,winforms,asynchronous,task,file-watcher,C#,Winforms,Asynchronous,Task,File Watcher,最近,我开始学习C#,编写了一个简单的应用程序,监视目录并根据写入该目录中文件的行更新表单。在某个时刻,我在尝试从FileWatcher事件更新表单元素时遇到了公共invalidooperationexception 我搜索了stackoverflow,似乎在这种情况下我使用了基于任务的异步模式(TAP),但我不知道应该将哪个方法标记为async,以及将哪个方法作为任务启动。关于stackoverflow有很多相关问题,但我发现没有一个问题涵盖了我的应用程序的所有3个方面: 使用FileWat

最近,我开始学习C#,编写了一个简单的应用程序,监视目录并根据写入该目录中文件的行更新表单。在某个时刻,我在尝试从
FileWatcher
事件更新表单元素时遇到了公共
invalidooperationexception

我搜索了stackoverflow,似乎在这种情况下我使用了基于任务的异步模式(TAP),但我不知道应该将哪个方法标记为
async
,以及将哪个方法作为
任务启动。关于stackoverflow有很多相关问题,但我发现没有一个问题涵盖了我的应用程序的所有3个方面:

  • 使用
    FileWatcher
  • 更新
    表单
    元素
  • 使用水龙头
那么,如果我想使用基于任务的异步模式,从FileWatcher触发的事件更新表单元素的最佳实践是什么?还是应该使用另一种模式/另一种应用程序结构

以下是我的应用程序的简化示例:

// 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);
        }
    }

}
更新21.07

看来我对使用TAPeverywhere的想法是错误的,因此我最终通过调用包含我的
SetSomeVaue
方法的委托来实现这一点,并且它工作正常(我希望这是一个正确的决定)


感谢您的回复

有帮助吗?@user3185569我还没有尝试调用委托,因为根据回答,我似乎应该在.NET 4.5+中使用TAP。我认为您不能将TPL与
FileSystemWatcher
一起使用。TAP与FileSystemWatcher是EAP有什么关系。而这两者并不是相互排斥的。您应该为FileWatcher使用EAP,因为使用EAP更好。您可以将任何事件转换为任务,但在这种情况下不应执行。调用和调用同步与EPL的TAP无关。但通常的FSW场景涉及持续监视;这是基于队列的,而不是基于任务的。也许在您的场景中,使用专用线程来消费数据的
BlockingCollection
更合适。很难说……问题很广泛。