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