C# WinC窗体我的ui仍然冻结在事件加载中使用异步

C# WinC窗体我的ui仍然冻结在事件加载中使用异步,c#,.net,winforms,asynchronous,async-await,C#,.net,Winforms,Asynchronous,Async Await,在我的窗体的事件加载中,我调用一个方法loadDg: 及 在我的代码中,db.row此方法始终只返回1行字符串数组,但我的ui仍然冻结,我尝试在启动时使用async连续更新ui而不冻结您正在同步调用loadDg函数 除非等待loadDg函数调用,因为它的返回类型是Task并使form_Load函数异步,否则函数调用将是同步的 正确的解决方法是 private async void form_Load(object sender, EventArgs e) { await loadDg();

在我的窗体的事件加载中,我调用一个方法loadDg:

在我的代码中,db.row此方法始终只返回1行字符串数组,但我的ui仍然冻结,我尝试在启动时使用async连续更新ui而不冻结您正在同步调用loadDg函数

除非等待loadDg函数调用,因为它的返回类型是Task并使form_Load函数异步,否则函数调用将是同步的

正确的解决方法是

private async void form_Load(object sender, EventArgs e)
{
  await loadDg();
}

没有什么可以阻止代码异步运行。即使在任务完成之前,pictureLoading也将不可见。您应该修复UI的跨线程问题和逻辑,如下所示:

private void form_Load(object sender, EventArgs e)
{
  pictureLoading.Visible = true;
  loadDg();
}


private async Task loadDg()
{

    await Task.Run(() =>
    {
        string[] datas = db.row("select * from products");
        string[] datas2 = db.row("select * from users");
        double one = Convert.ToInt32(datas[0]);

        label1.BeginInvoke((Action)delegate ()
        {
            label1.Text = one.toString();
            //hide gif animation 
            pictureLoading.Visible = false;
        });
        //....
    });

}

应避免线程/上下文之间不必要的跳跃

这是一个资源利用率更好的解决方案:

private async void form_Load(object sender, EventArgs e)
{
    pictureLoading.Visible = true;

    try
    {
        label1.Text = await LoadDgAsync();
    }
    catch
    {
        // error handling
    }
    finally
    {
        pictureLoading.Visible = false;
    }
}


private Task<string> LoadDgAsync()
{
    return Task.Run(() =>
    {
        string[] datas = db.row("select * from products");
        string[] datas2 = db.row("select * from users");
        double one = Convert.ToInt32(datas[0]);

        //....

        return one.toString();
    });
}

label1.Text=。。。在非ui中,线程是坏的。@Sinatr修复它的最佳方法是什么?@Flydog57 loadDg不是同步调用的。给定所示内容,它是一个异步方法,在所示代码中完成之前,没有任何东西会显式阻塞,因此它将异步运行。只有当您需要对异步方法的完成做出响应时,才可以将form_Load标记为async。在本例中,当它完成时没有任何操作。。。问题中,创建一个小函数来设置标签并使用控件。要在拥有控件的线程上调用该函数,请记住Form类是控件的子类。关于如何做到这一点,有很多例子。这是错误的。调用异步方法不会同步运行它。如果该方法从一开始就是一个同步方法,那么它将只同步运行,如果这是真的,那么该代码的行为将不会有任何不同,并且也将同步运行它。wait是一个工具,用于在异步方法完成后更方便地执行某些操作。由于异步方法完成时,此代码与此无关,它一事无成。@Servy也许你可以推荐另一种最好的方法来解决这个问题?@kevin73你需要提供足够的代码来重现这个问题,以便任何人告诉你如何解决它。从线程池线程调用UI线程并立即返回UI线程有什么好处?@PauloMorgado简单的情况下,您的解决方案会更好。但是,如果任务是一个循环,并且您希望多次更新UI,那么上面的代码就可以了,但在以后的情况下,有时BackgroundWorker也可以工作。或IProgress。但是,在这种情况下,你不会隐藏图片阅读。你愿意吗?@PauloMorgado 1。我试图用最少的代码更改来解决这个问题。2.该问题在不同行中有多个UI更新。因此,这样做可能更容易。3.此外,该方法在FormLoad中运行一次,这不会让我担心资源使用情况。
private void form_Load(object sender, EventArgs e)
{
  pictureLoading.Visible = true;
  loadDg();
}


private async Task loadDg()
{

    await Task.Run(() =>
    {
        string[] datas = db.row("select * from products");
        string[] datas2 = db.row("select * from users");
        double one = Convert.ToInt32(datas[0]);

        label1.BeginInvoke((Action)delegate ()
        {
            label1.Text = one.toString();
            //hide gif animation 
            pictureLoading.Visible = false;
        });
        //....
    });

}
private async void form_Load(object sender, EventArgs e)
{
    pictureLoading.Visible = true;

    try
    {
        label1.Text = await LoadDgAsync();
    }
    catch
    {
        // error handling
    }
    finally
    {
        pictureLoading.Visible = false;
    }
}


private Task<string> LoadDgAsync()
{
    return Task.Run(() =>
    {
        string[] datas = db.row("select * from products");
        string[] datas2 = db.row("select * from users");
        double one = Convert.ToInt32(datas[0]);

        //....

        return one.toString();
    });
}