处理任务中的事件;在Task中处理来自WebBrowser的导航事件?

时间:2015-12-02 17:16:29

标签: c#

我正在重写一些使用WebBrowser对象的代码,以确定服务器何时可以下载文件。总的来说,行为是这样的,首先将文件上传到服务器,一旦上传服务器然后开始工作,因为它正在工作,它将连接到它所服务的特定页面的用户重定向到各种URL,直到它完成,一次完成后,文件就可以下载了。

我希望在单个函数调用中具有所有这些行为,基本上是GetFileFromServer()。一旦此调用返回,则文件位于指定的文件路径。

问题是当使用WebBrowser我必须处理Navigated事件以确定文件何时可以下载时,这会使程序流离开GetFileFromServer函数。我可以有一个小的循环

while(fileNotDownloaded)
    Thread.Sleep(500);

但我想改用Task,以便该函数看起来像

public void GetFileFromServer()
{
    UploadFile();   // Blocks until file is uploaded
    DownloadFile(); // Blocks until file is downloaded
}

我已经实施了UploadFile但是,再次遇到DownnloadFile的问题。基本上我希望我的功能看起来像这样

private void DownloadFile()
{
    var DoWebDriverTask = Task.Factory.StartNew(() =>
    {
        Boolean fileReady = false;
        WebBrowser webBrowser = new WebBrowser();
        webBrowser.Url = new Uri(MySpecificIP);
        webBrowser.Navigated += WebBrowserNavigated;

        // Sit and Spin until the specific URL is navigated to
        while(!fileReady)
            Task.WaitAll(new Task[] { Task.Delay(500) });

        DownloadFile();

        private void WebBrowserNavigated(object sender, WebBrowserNavigatedEventArgs e)
        {
            if(e.Url.AbsoluteUri.ToString().Contains("mySpecificURLString"))
                fileReady = true;
        }
    }, CancelWaitForDownloadTaskToken);
    Task.WaitAll(new Task[] { WebDriverTask });
}

但这显然不是正确的代码。我也理解这是我在上面提供的解决方案,但只是移到了Task,但它确实给了我GetFileFromServer的行为。请注意,UI线程中没有一个是按原样进行的,所以我上面提供的解决方案也是可行的...但是使用Task如果用户我可以取消等待下载希望。

那么有没有办法处理Navigated中的事件Task,正如我在上面的代码中描述的那样?

1 个答案:

答案 0 :(得分:1)

以下是在同一方法范围内处理事件的方法:

webBrowser.Navigated += (s, e) =>
{
    if (e.Url.AbsoluteUri.ToString().Contains("mySpecificURLString"))
        fileReady = true;
};

然而,循环和等待不是一个好主意,这是一个更好的选择:

private Task WaitBeforeDownloadFile(WebBrowser webBrowser)
{
    TaskCompletionSource<bool> tcs = new TaskCompletionSource<bool>();

    WebBrowserNavigatedEventHandler web_browser_on_navigated = null;

    web_browser_on_navigated = (s, e) =>
    {
        if (e.Url.AbsoluteUri.ToString().Contains("mySpecificURLString"))
        {
            tcs.TrySetResult(true);

            webBrowser.Navigated -= web_browser_on_navigated;
        }
    };

    webBrowser.Navigated += web_browser_on_navigated;

    return tcs.Task;
}

此方法创建Task,在Navigated事件被引发并满足您指定的条件时完成。

以下是您将如何使用它:

private void DownloadFile()
{
    WebBrowser webBrowser = new WebBrowser();
    webBrowser.Url = new Uri(MySpecificIP);

    //Initiate whatever here before waiting for the Navigated event

    WaitBeforeDownloadFile(webBrowser).Wait();

    //Continue here
}

这也不是一件好事。但是,由于您需要同步行为,因此您必须这样做。

一个更好的替代方案,需要对你的工作方式做很多改变,就是异步做事,这需要大量的学习。这是一个例子:

public async Task GetFileFromServer()
{
    await UploadFile();
    await DownloadFile();
}

public async Task UploadFile()
{
    ...
}

public async Task DownloadFile()
{
    WebBrowser webBrowser = new WebBrowser();
    webBrowser.Url = new Uri(MySpecificIP);

    //Initiate whatever here before waiting for the Navigated event

    await WaitBeforeDownloadFile(webBrowser);

    //Continue here
}