Иногда ожидание бывает дольше, чем хотелось бы пользователю. И если во время этого ожидания приложение еще и не реагирует на действия пользователя, то он вообще в гневе. Достаточно давно, я уже писал как можно реализовать многопоточное приложение. В Framework 4.5 появилась пара ключевых слов, которые позволяют реализовать еще один механизм выолнения длительной операции в отдельном потоке. Это слова async и await.
В качестве примера возьмем загрузку ежедневных курсов с сайта Центробанка России. У них если кто не знает, по адресу http://www.cbr.ru/DailyInfoWebServ/DailyInfo.asmx есть соответствующий сервис.
Итак создаем WPF приложение. Правым кликом на проекте в Solution Explorer-е и выбираем добавить ссылку на сервис (Add Service Reference):
В главную форму нашего приложения кидаем DataGrid и подписываемся на обработчик окончания загрузки окна:
Обработчик будет выглядеть вот так:
Ну и результат:
Единственный недостаток, это то, что приложение "подвисает" на время загрузки данных. Давайте применим async и await для решения данной задачи. Что придется изменить? Совсем немного:
Как видно, изменений всего ничего:
1. Метод помечен async.
2. Вызывается не метод GetCursOnDate, а GetCursOnDateAsync. Данный метод возвращает Task.
3. Чтобы дождаться результата выполнения запущенного в отдельном потоке и Task преобразовать к DataSet нам и нужно второе ключевое слово await.
Собственно все.
В качестве примера возьмем загрузку ежедневных курсов с сайта Центробанка России. У них если кто не знает, по адресу http://www.cbr.ru/DailyInfoWebServ/DailyInfo.asmx есть соответствующий сервис.
Итак создаем WPF приложение. Правым кликом на проекте в Solution Explorer-е и выбираем добавить ссылку на сервис (Add Service Reference):
В главную форму нашего приложения кидаем DataGrid и подписываемся на обработчик окончания загрузки окна:
<Window
x:Class="CourseOnDay.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow"
Height="350"
Width="525"
Loaded="Window_Loaded_1">
<Grid>
<DataGrid
x:Name="dgMain"
/>
</Grid>
</
Window>
Обработчик будет выглядеть вот так:
private void Window_Loaded_1(object sender, RoutedEventArgs e)
{
CBR.DailyInfoSoapClient client = new CBR.DailyInfoSoapClient();
DataTable result = client.GetCursOnDate(DateTime.Now).Tables[0];
dgMain.ItemsSource =
result.Rows.Cast<DataRow>().Select(
r
=> new
{
Валюта =
r[0],
Количество =
r[1],
Стоимость =
r[2]
}
);
}
Ну и результат:
Единственный недостаток, это то, что приложение "подвисает" на время загрузки данных. Давайте применим async и await для решения данной задачи. Что придется изменить? Совсем немного:
private async void Window_Loaded_1(object sender, RoutedEventArgs e)
{
CBR.DailyInfoSoapClient client = new CBR.DailyInfoSoapClient();
DataSet result = await client.GetCursOnDateAsync(DateTime.Now);
dgMain.ItemsSource = result.Tables[0].Rows.Cast<DataRow>().Select(
r
=> new
{
Валюта =
r[0],
Количество =
r[1],
Стоимость =
r[2]
}
);
}
Как видно, изменений всего ничего:
1. Метод помечен async.
2. Вызывается не метод GetCursOnDate, а GetCursOnDateAsync. Данный метод возвращает Task
3. Чтобы дождаться результата выполнения запущенного в отдельном потоке и Task преобразовать к DataSet нам и нужно второе ключевое слово await.
Собственно все.
Спасибо познавательно, не подскажешь как организовать progress bar пока выполняется GetCursOnDateAsync(DateTime.Now)??
ОтветитьУдалитьК сожалению, в данном случае показать ProgressBar не получится, т.к. метод не предоставляет информацию о прогрессе как таковом. Есть факт запуска и факт окончания загрузки. Мы в таких случаях показываем не ProgressBar, а "мотылятор". "Мотылятор" это компонент который показывает некую анимацию во время загрузки. Например кружочки бегут по кругу. Т.е. мы пользователю говорим, что работа идет, но, к сожалению, без индикатора успешности процесса.
УдалитьGetCursOnDateAsync(DateTime.Now).Status а это тогда что?
ОтветитьУдалитьДело в том, что Async методы возвращают, на самом деле экземпляр класса Task. Если еще не читали, то прочитайте вот это http://losev-al.blogspot.ru/2012/10/blog-post_16.html У класса Task есть свойство Status, в котором храниться перечисление со значениями: выполняется, остановлен, ошибка, завершен и т.д. Вы сможете на основе этих значений вывести сколько процентов скачалось? Я нет...
Удалить