【问题标题】:Async/Await Multi functions异步/等待多功能
【发布时间】:2013-09-18 00:30:06
【问题描述】:

我正在尝试制作一个简单的应用程序来加载数据并对其执行操作。所以我的想法是异步进行。

我有 3 个数据源,我想异步加载它们。因此,例如 Data1.xml、Data2.xml 和 Data3.xml,所有文件都非常大,需要一些时间才能加载(这就是我想要异步的原因)。

例如,我创建了一个带有 3 个文本框的窗口,这些文本框都绑定到特定属性(Text1、Text2、Text3)和一个按钮。当我单击按钮时,我想异步执行 3 个函数(MakeText1,MakeText2,...)。我将 MakeText3 设为禁食,所以通常我必须先看到 Text3。它不起作用,我做错了什么?

private string _text1;

    public string Text1
    {
        get { return _text1; }
        set { _text1 = value;
        if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs("Text1"));
        }
    }

    private string _text2;

    public string Text2
    {
        get { return _text2; }
        set
        {
            _text2 = value;
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs("Text2"));
        }
    }

    private string _text3;

    public string Text3
    {
        get { return _text3; }
        set
        {
            _text3 = value;
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs("Text3"));
        }
    }

    public AsyncWin()
    {
        InitializeComponent();
        this.DataContext = this;
    }

    private async Task MakeText1()
    {
        for (double i = 0; i < 7000000; i++)
        {
            _text1 = i.ToString();
        }
        Text1 = _text1;
    }
    private async Task MakeText2()
    {
        for (double i = 0; i < 3000; i++)
        {
            _text2 = i.ToString();
        }
        Text2 = _text2;
    }
    private async Task MakeText3()
    {
        for (double i = 0; i < 10; i++)
        {
            _text3 = i.ToString();
        }
        Text3 = _text3;
    }

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        _text1 = "";
        _text2 = "";
        _text3 = "";
        Test();
        Console.WriteLine();
    }
    public async void Test()
    {
        MakeText1();
        MakeText2();
        MakeText3();
    }
    public event PropertyChangedEventHandler PropertyChanged;

Xaml:

    <Grid>
    <TextBox x:Name="txt1" HorizontalAlignment="Left" Height="181" Margin="10,19,0,0" TextWrapping="Wrap" Text="{Binding Text1}" VerticalAlignment="Top" Width="110"/>
    <TextBox x:Name="txt2" HorizontalAlignment="Left" Height="181" Margin="137,19,0,0" TextWrapping="Wrap" Text="{Binding Text2}" VerticalAlignment="Top" Width="110"/>
    <TextBox x:Name="txt3" HorizontalAlignment="Left" Height="181" Margin="276,19,0,0" TextWrapping="Wrap" Text="{Binding Text3}" VerticalAlignment="Top" Width="110"/>
    <Button Content="Button" HorizontalAlignment="Left" Margin="10,219,0,0" VerticalAlignment="Top" Width="75" Click="Button_Click"/>
</Grid>

【问题讨论】:

  • 所有 MakeTextN 方法都是同步的。它们同步运行,然后返回一个完成的任务。如果你想让它们在后台线程上运行,你应该使用 Task.Run
  • 谢谢这工作正常,但异步可以吗?
  • 使用关键字async 不会使方法异步。是这个意思吗?
  • 是的。但是有没有办法用 async/await 做到这一点?
  • 是的。非UI工作使用Task.Run,await返回Task,然后更新UI元素。

标签: c# wpf asynchronous async-await


【解决方案1】:

我希望 UI 先显示 Text3 而不是 Text2

这不会在您的代码中发生,因为Text1..Text3 的设置器内的人工延迟循环会同步运行,而不会让其他任务执行。如果将这些循环替换为Task.Delay(...),就会得到想要的效果:

private async Task MakeText1() {
    await Task.Delay(3000);
    Text1 = "3 seconds";
}
private async Task MakeText2() {
    await Task.Delay(2000);
    Text2 = "2 seconds";
}
private async Task MakeText3() {
    await Task.Delay(1000);
    Text3 = "1 second";
}

【讨论】:

  • 无法从 void 方法返回。
  • 是的,但我希望如果 MakeText3 在其他人之前完成,他会显示他的数据,而不是我必须等到其他人完成。
  • 我明白,但我试过了,首先代码给出了错误。我希望 UI 先显示 Text3 而不是 Text2
  • 你为什么在Test()中显式调用PropertyChanged?此外,您在Task.WhenAll() 之前缺少await。
  • @svick 我添加了对PropertyChanged 的调用,因为 OP 设置了“支持”相应属性的私有变量,而不是设置属性本身。我本可以将await 放在Task.WaitAll 前面,但我把它放在await Test(); 中。我在本地运行了这段代码,它产生了预期的效果。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-09-10
  • 1970-01-01
  • 2019-04-22
  • 2020-02-15
  • 2021-10-05
  • 2021-08-23
  • 2023-04-08
相关资源
最近更新 更多