Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/323.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/21.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 在Windows窗体中使用webbrowser控件处理非UI阻塞_C#_.net_Async Await_Task_Webbrowser Control - Fatal编程技术网

C# 在Windows窗体中使用webbrowser控件处理非UI阻塞

C# 在Windows窗体中使用webbrowser控件处理非UI阻塞,c#,.net,async-await,task,webbrowser-control,C#,.net,Async Await,Task,Webbrowser Control,我有一个带有webbrowser控件(此处为wb)的小型windows窗体应用程序,它执行一些任务,如登录门户、搜索项目、更改某些属性/复选框以及提交表单。 完成的每一步都是通过更改标签的文本来宣布的,这样用户就可以看到当前所做的事情 处理与webbrowser控件交互的最佳方式是什么,这样UI就不会被阻塞 我这样试过: private async void buttonStart_Click(object sender, EventArgs e) { //Here it is stil

我有一个带有webbrowser控件(此处为wb)的小型windows窗体应用程序,它执行一些任务,如登录门户、搜索项目、更改某些属性/复选框以及提交表单。 完成的每一步都是通过更改标签的文本来宣布的,这样用户就可以看到当前所做的事情

处理与webbrowser控件交互的最佳方式是什么,这样UI就不会被阻塞

我这样试过:

private async void buttonStart_Click(object sender, EventArgs e)
{
    //Here it is still possible to access the UI thread
    buttonStart.Enabled = false;

    //do the background work
    await Task.Run(() =>
    {
        Login();
        CallProject();
        TriggerTask1();
        TriggerTask2();
    });

    //back on UI thread
    buttonStart.Enabled = false;
}

private void Login()
{
    //may not access labelProgress from this thread
    //labelProgress.Text = "logging in";

    Invoke(new Action(() =>
    {
        //can access labelProgress here
        labelProgress.Text = "logging in";

        //can access wb here
        wb.Navigate(Settings.Default.LoginUrl);
        WebBrowserTools.Wait(wb);

        wb.Document.GetElementById("username").InnerText = Settings.Default.LoginUsername;
        wb.Document.GetElementById("password").InnerText = Settings.Default.LoginPassword;
        wb.Document.Forms[0].InvokeMember("submit");
        WebBrowserTools.Wait(wb);

        labelProgress.Text = "logged in successfully";
    }));
}
对webbrowser或任何其他ui控件(如labelProgress)的每次访问都必须包装在
Invoke(新操作(()=>{})中
有没有更好的方法(使用.NET Framework>=4.5的现代版本)?

您使用的是异步等待,而不是预期的方式

。在中间搜索某处,等待。< /P> 他把异步等待比作厨师必须做早餐。在他把水壶烧开水沏茶后,他可以决定什么都不做,直到水烧开,然后他沏茶并开始烤面包。在面包烤好之前不要做任何事

如果厨师在等待另一个过程结束时,在等待第一件事情完成之前,开始做其他事情,而不是什么都不做,那么速度会快得多:

Start boiling water
Start toasting bread
wait until the water boils
use the boiling water to start making tea
...
您将看到async wait通常出现在线程命令某个进程执行线程自己无法执行的操作时:从数据库获取数据、将数据写入文件、从internet获取数据:线程只能等待的操作

你正确地开始了你的程序。你的厨师做了一些准备工作,但是他决定他应该雇佣另一个厨师为他做这项工作,而你的厨师什么也不做,只是等到另一个厨师完成工作。你的厨师为什么不这么做

更典型的异步等待如下所示:

async void buttonStart_Click(object sender, EventArgs e)
{
    buttonStart.Enabled = false;

    await LoginAsync();
    await CallProjectAsync();
    await TriggerTask1Async();
    await TriggerTask2Async();

    buttonStart.Enabled = false;
}
通常,如果您使用支持async Wait的对象,这将起作用。对于每个异步函数,您都知道在某个地方有一个对可等待的异步函数的调用。事实上,如果您在不等待任何调用的情况下声明函数为async,编译器会抱怨

唉,有时候你的厨师在做其他事情时,不能依靠一个过程来继续。这是因为WebBrowser类不像WebClient类那样支持异步等待

这类似于当你的厨师不得不做一些繁重的处理时,你仍然想保持你的程序异步等待,比如切西红柿:水壶会自动煮沸水,你需要另一个厨师来切西红柿

在异步等待场景中,通常会使用Task.Run。在您的情况下,这是例如在您的登录功能

async void LoginAsync()
{
    // still main thread. Notify the operator:
    labelProgress.Text = "logging in";

    // we start something that takes some time that this cook can't spend:
    // let another cook do the logging in
    await Task.Run( () =>
    {
        wb.Navigate(Settings.Default.LoginUrl);
        WebBrowserTools.Wait(wb);
        wb.Document.GetElementById("username").InnerText = Settings.Default.LoginUsername;
        wb.Document.GetElementById("password").InnerText = Settings.Default.LoginPassword;
        wb.Document.Forms[0].InvokeMember("submit");
        WebBrowserTools.Wait(wb);
    }

    // back in main thread:
    labelProgress.Text = "logged in successfully";
}

所以诀窍是:尽可能多地使用异步等待准备好的类。只有当你的厨师不得不做一些冗长的事情,但他想自由地做其他事情时,才可以执行Task.Run()。等待你的厨师需要确定另一个厨师完成了任务的时候。当你有其他事情要做时,不要等待。让您的厨师来处理用户界面。

您正在以一种非预期的方式使用async await

。在中间搜索某处,等待。< /P> 他把异步等待比作厨师必须做早餐。在他把水壶烧开水沏茶后,他可以决定什么都不做,直到水烧开,然后他沏茶并开始烤面包。在面包烤好之前不要做任何事

如果厨师在等待另一个过程结束时,在等待第一件事情完成之前,开始做其他事情,而不是什么都不做,那么速度会快得多:

Start boiling water
Start toasting bread
wait until the water boils
use the boiling water to start making tea
...
您将看到async wait通常出现在线程命令某个进程执行线程自己无法执行的操作时:从数据库获取数据、将数据写入文件、从internet获取数据:线程只能等待的操作

你正确地开始了你的程序。你的厨师做了一些准备工作,但是他决定他应该雇佣另一个厨师为他做这项工作,而你的厨师什么也不做,只是等到另一个厨师完成工作。你的厨师为什么不这么做

更典型的异步等待如下所示:

async void buttonStart_Click(object sender, EventArgs e)
{
    buttonStart.Enabled = false;

    await LoginAsync();
    await CallProjectAsync();
    await TriggerTask1Async();
    await TriggerTask2Async();

    buttonStart.Enabled = false;
}
通常,如果您使用支持async Wait的对象,这将起作用。对于每个异步函数,您都知道在某个地方有一个对可等待的异步函数的调用。事实上,如果您在不等待任何调用的情况下声明函数为async,编译器会抱怨

唉,有时候你的厨师在做其他事情时,不能依靠一个过程来继续。这是因为WebBrowser类不像WebClient类那样支持异步等待

这类似于当你的厨师不得不做一些繁重的处理时,你仍然想保持你的程序异步等待,比如切西红柿:水壶会自动煮沸水,你需要另一个厨师来切西红柿

在异步等待场景中,通常会使用Task.Run。在您的情况下,这是例如在您的登录功能

async void LoginAsync()
{
    // still main thread. Notify the operator:
    labelProgress.Text = "logging in";

    // we start something that takes some time that this cook can't spend:
    // let another cook do the logging in
    await Task.Run( () =>
    {
        wb.Navigate(Settings.Default.LoginUrl);
        WebBrowserTools.Wait(wb);
        wb.Document.GetElementById("username").InnerText = Settings.Default.LoginUsername;
        wb.Document.GetElementById("password").InnerText = Settings.Default.LoginPassword;
        wb.Document.Forms[0].InvokeMember("submit");
        WebBrowserTools.Wait(wb);
    }

    // back in main thread:
    labelProgress.Text = "logged in successfully";
}

所以诀窍是:尽可能多地使用异步等待准备好的类。只有当你的厨师不得不做一些冗长的事情,但他想自由地做其他事情时,才可以执行Task.Run()。等待你的厨师需要确定另一个厨师完成了任务的时候。当你有其他事情要做时,不要等待。让你的厨师来处理用户界面。

调用UI线程上的调用,这将反过来阻止UI。你刚刚想出了一个绝妙的方法。只调用
UI部件并异步调用
WebBrowserTools怎么样?从任务中等待?那是