Here is what i have tried - It works, as far as seeing the UI refreshed, but i don't think it's the best use of async / await. How can i improve on this?
private async void btnQuickTest_Click(object sender, RoutedEventArgs e)
{
    XmlReader reader;
    int rowCount = 0;
    using (reader = XmlReader.Create("someXmlFile.xml"))
    {
        while (reader.Read())
        {
            rowCount++;
            DoSomeProcessingOnTheUIThread(reader);
            //only update UI every 100 loops
            if (rowCount > 0 && rowCount % 100 == 0)
            {
                //yay! release the UI thread
                await Task.Run(() =>
                {
                    Application.Current.Dispatcher.Invoke(
                        () =>
                        {
                            txtRowCount.Text = string.Format("{0}", rowCount);
                        });
                });
            }
        } //end-while
    }//end-using
}
What's a better approach?
UPDATE: I have avoided the Dispatcher.Invoke based on the answer of Clemens, by sending the processing to a background task, and updating progress on the UI directly. My code now looks like.
private async void btnQuickTest_Click(object sender, RoutedEventArgs e)
{
    XmlReader reader;
    int rowCount = 0;
    using (reader = XmlReader.Create("someXmlFile.xml"))
    {
        while (reader.Read())
        {
            rowCount++;
            await DoSomeProcessing(reader);
            //only update UI every 100 loops
            if (rowCount % 100 == 0)
            {
                txtRowCount.Text = string.Format("{0}", rowCount);
            }
        } //end-while
    }//end-using
    MessageBox.Show("I am done!");
}
private Task DoSomeProcessing(XmlReader reader)
{
   Task t =Task.Run(() =>
   {
       //Do my processing here.
   });
   return t;
}
UPDATE#2: On reflection, why am i creating a new Task on every loop ? It would probably be better to just run the whole loop within one background task. And periodically raise a callback to show progress; See my other answer below.
A Task that immediately calls Dispatcher.Invoke is pointless, because there is nothing that actually runs on a background thread, except the tiny piece of code that schedules the Dispatcher action.
Better set the Text property directly, and use XmlReader.ReadAsync:
private async void btnQuickTest_Click(object sender, RoutedEventArgs e)
{
    using (var reader = XmlReader.Create("someXmlFile.xml"))
    {
        int rowCount = 0;
        while (await reader.ReadAsync())
        {
            rowCount++;
            await Task.Run(() =>
            {
                DoSomeWork(reader);
            });
            if (rowCount > 0 && rowCount % 100 == 0)
            {
                txtRowCount.Text = string.Format("{0}", rowCount);
            }
        }
    }
}
You may also consider making your DoSomeWork async and directly call it like this:
await DoSomeWork(reader);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With