1

I'am trying to make a simple application that loads data and performs an action on it. So my idea was to do this async.

I have 3 data sources and i would like to load them async. So for example Data1.xml, Data2.xml and Data3.xml all files are quite big to load so it takes some time (that's why i would like async).

So for example i made a window with 3 Textboxes that all bind to a specific property (Text1, Text2, Text3) and a button. When i click on the button i would like to execute 3 functions async (MakeText1,MakeText2, ...). I made MakeText3 the fastes one so normally i would have to see Text3 first. It doesn't work, what am i doing wrong?

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>
5
  • 2
    All of your MakeTextN methods are synchronous. They run synchronously and then return a completed Task. If you want them to run on a background thread, you should use Task.Run Commented Sep 17, 2013 at 13:40
  • Thanks this works fine but is it possible with async ? Commented Sep 17, 2013 at 13:52
  • using the keyword async doesn't make the method asynchronous. Is that what you mean? Commented Sep 17, 2013 at 17:38
  • Yes. But is there a way to do this with async/await? Commented Sep 18, 2013 at 12:24
  • Yes. Use Task.Run for the non-UI work, await the returned Task and then update the UI element. Commented Sep 18, 2013 at 13:47

1 Answer 1

3

I would like that the UI show Text3 first than Text2

This does not happen in your code, because the artificial delay loops inside the setters for Text1..Text3 runs synchronously, without letting other tasks having a go. If you replace these loops with Task.Delay(...), you will get the desired effect:

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";
}
Sign up to request clarification or add additional context in comments.

7 Comments

Cannot return from a void method.
Yes but i would like that if MakeText3 is finished before the others, he show his data and not that i have to wait untill the others are finished.
I understand but i tried this and first of all the code gives errors. And i would like that the UI show Text3 first than Text2
Why are you explicitly calling PropertyChanged in Test()? Also, you're missing await before Task.WhenAll().
@svick I added a call to PropertyChanged because OP sets the private variables that "back" the corresponding properties, instead of setting the properties themselves. I could have put await in front of Task.WaitAll, but I put it into await Test(); instead. I ran this code locally, and it produced the desired effect.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.