Цель работы: освоить технологию работы с классом BackgroundWorker
Создавая простое приложение для Windows Phone, не выполняющее сложных вычислений, не обращающееся к веб-сервисам, не выполняющее работу с файлами, о выполнении каких-либо задач вне потока пользовательского интерфейса обычно не задумываются. Если мы, например, в обработчике события нажатия на кнопку захотим выполнить какое-то простое вычисление, или проверку какого-либо условия, вычислительная нагрузка от таких операций ляжет на поток пользовательского интерфейса. До тех пор, пока эта нагрузка незначительна, подобное не сказывается на скорости отклика приложения. Но если нужно выполнить какую-либо ресурсоёмкую операцию, это можно сделать и без дополнительных усилий по использованию для неё другого потока, однако, выполнение её в потоке пользовательского интерфейса приведет к заметным задержкам. Как вы увидите в примере, который мы разберем в этой лабораторной работе, интерфейс может быть блокирован. То есть, приложение не реагирует на взаимодействие пользователя с элементами управления, анимация может либо приостановиться, либо работать рывками.
В предыдущих лабораторных работах мы сталкивались с вызовом асинхронных методов для выполнения задач, которые могут занимать потенциально достаточно большое время. При объявлении метода, в котором мы вызывали асинхронные операции, используется модификатор async, операция вызывается с использованием оператора await. Это приводит к тому, что выполнение метода приостанавливается до тех пор, пока не будет получен ответ от вызываемой процедуры. Например – данные, загруженные с веб-сервера. При этом использование async и await упрощает написание асинхронного кода, так как до появления этого механизма (это произошло в Visual Studio 2012) при вызове асинхронного метода нужно было предусматривать использование функции, которая вызывается при завершении работы метода и обрабатывает полученные результаты. Такой подход применим и сейчас, но он усложняет структуру кода, в то время как асинхронный код, написанный с использованием async и await, хотя и решает задачи асинхронной обработки, выглядит как синхронный.
До сих пор мы вызывали асинхронные методы каких-либо объектов, но нередко возникают задачи, для успешного решения которых нужно асинхронно выполнить произвольный код. То есть, выполнить этот код не в потоке пользовательского интерфейса, а в другом потоке. При таком подходе интерфейс продолжает реагировать на воздействия пользователя. Решить подобную задачу можно, например, с использованием класса ).
Он предоставляет средства для выполнения операций в потоках, отличных от потока пользовательского интерфейса. Рассмотрим пример, иллюстрирующий работу с BackgroundWorker.
В основу этого примера положен пример "Work with ProgressIndicator and hide", http://code.msdn.microsoft.com/Work-with-ProgressIndicator-545eb39d. Здесь представлен русифицированный код, снабжённый дополнительными комментариями и дополнениями, иллюстрирующими недостатки синхронного выполнения задач, аналогичных тем, которые решаются с помощью выполнения задач в потоке, отличном от потока пользовательского интерфейса. В частности, здесь к исходному коду, добавлена демонстрация того, как выполнение ресурсоёмкой задачи в потоке пользовательского интерфейса блокирует анимацию, делает невозможной нормальную работу с элементами управления пользовательского интерфейса. Рекомендуется при освоении этого примера загрузить его по указанной ссылке, так как в него могут быть внесены дополнения и обновления, а код, приведенный здесь, использовать как справочное руководство.
В исходном примере так же показана работа с индикатором выполнения, который сигнализирует пользователю о том, что в настоящий момент выполняется какая-либо ресурсоёмкая задача. В подобных задачах такой подход весьма актуален, так как пользователю нужно сообщать о том, что приложение выполняет какую-то ресурсоёмкую задачу и пользователю, для выполнения результатов, следует некоторое время подождать. При этом весьма желательно указывать время, которое может занять выполнение задачи. В нашем случае мы искусственно создаём 5-секундную задержку, которая имитирует сложную вычислительную задачу. В реальных условиях, если неизвестно точно, сколько времени будет выполняться операция, экспериментальным путём можно выяснить хотя бы приблизительное время и сообщить об этом пользователю.
На рис. 22.1. вы можете видеть окно проекта.
(рис 43.1) Окно проекта
На главной странице (Листинг 43.1) присутствуют кнопки Выполнить асинхронно и Выполнить синхронно, запускающие выполнение имитации ресурсоёмкой задачи, на выполнение которой нужно 5 секунд, соответственно, асинхронно, в дополнительном потоке, и синхронно, в потоке пользовательского интерфейса. Прямоугольник на странице анимирован – для демонстрации того, как синхронное выполнение ресурсоёмких задач влияет на пользовательский интерфейс. Флаг Проверьте отклик интерфейса позволяет проверить реакцию интерфейса в ходе синхронного и асинхронного выполнения задачи.
<phone:PhoneApplicationPage
x:Class="CSWP8ProgressIndicator.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
FontSize="{StaticResource PhoneFontSizeNormal}"
Foreground="{StaticResource PhoneForegroundBrush}"
SupportedOrientations="Portrait" Orientation="Portrait"
shell:SystemTray.IsVisible="True">
<phone:PhoneApplicationPage.Resources>
<Storyboard x:Name="Storyboard1">
<ColorAnimationUsingKeyFrames Storyboard.TargetProperty="(Shape.Fill).
(SolidColorBrush.Color)" Storyboard.TargetName="rectangle">
<EasingColorKeyFrame KeyTime="0" Value="#FF1A1AEA"/>
<EasingColorKeyFrame KeyTime="0:0:5" Value="#FFEA1A1A"/>
</ColorAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).
(CompositeTransform.Rotation)" Storyboard.TargetName="rectangle">
<EasingDoubleKeyFrame KeyTime="0" Value="0"/>
<EasingDoubleKeyFrame KeyTime="0:0:5" Value="359.926"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</phone:PhoneApplicationPage.Resources>
<!--LayoutRoot is the root grid where all page content is placed-->
<Grid x:Name="LayoutRoot" Background="Transparent">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<!--TitlePanel contains the name of the application and page title-->
<StackPanel x:Name="TitlePanel" Grid.Row="0"
Margin="12,17,0,28">
<TextBlock Text="АСИНХРОННЫЙ КОД" Style="{StaticResource PhoneTextNormalStyle}" Margin="12,0"/>
<TextBlock Text="главная" Margin="9,-7,0,0"
Style="{StaticResource PhoneTextTitle1Style}"/>
</StackPanel>
<!--ContentPanel - place additional content here-->
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
<TextBlock x:Name="tbMessage"
Text="Нажмите на кнопку "Выполнить асинхронно" для начала выполнения фонового процесса.
Вы увидите идикатор выполнения. Когда задача будет завершена. индикатор будет скрыт,
будет выведено сообщение о завершении работы.
Нажмите на кнопку "Выполнить синхронно" для демонстрации синхронного выполнения
ресурсоёмкой задачи." TextWrapping="Wrap" ScrollViewer.VerticalScrollBarVisibility="Visible"/>
<Button x:Name="btnWork" Content="Выполнить асинхронно" HorizontalAlignment="Left" Margin="83,294,0,0"
VerticalAlignment="Top" Click="btnWork_Click"/>
<Rectangle x:Name="rectangle" Fill="#FFF4F4F5"
HorizontalAlignment="Left" Height="100" Margin="173,477,0,0"
Stroke="Black" VerticalAlignment="Top" Width="100"
RenderTransformOrigin="0.5,0.5">
<Rectangle.RenderTransform>
<CompositeTransform/>
</Rectangle.RenderTransform>
</Rectangle>
<Button x:Name="btnSyncWork" Content="Выполнить синхронно"
HorizontalAlignment="Left" Margin="83,374,0,0" VerticalAlignment="Top"
Click="btnSyncWork_Click" Width="305"/>
<CheckBox Content="Проверьте отклик интерфейса"
HorizontalAlignment="Left" Margin="10,222,0,0"
VerticalAlignment="Top"/>
</Grid>
</Grid>
</phone:PhoneApplicationPage>
В коде файла MainPage.xaml.cs (Листинг 2) показана работа синхронных механизмов (обработчик нажатия на кнопку btnSyncWork и асинхронных (их запуск производится при нажатии на кнопку btnWork.
using System;
using System.Windows;
using Microsoft.Phone.Controls;
using Microsoft.Phone.Shell;
using System.ComponentModel;
using System.Threading;
namespace CSWP8ProgressIndicator
{
public partial class MainPage : PhoneApplicationPage
{
static string strMsg = string.Empty; // Сообщение о результате.
// Конструктор
public MainPage()
{
InitializeComponent();
}
private void btnWork_Click(object sender, RoutedEventArgs e)
{
//Добавлено, воспроизведение анимации
Storyboard1.Begin();
// Создание и настройка нового индикатора выполнения
ProgressIndicator prog = new ProgressIndicator();
prog.IsVisible = true;
prog.IsIndeterminate = true;
prog.Text = "Выполнение задачи...";
//Установка нового индикатора
SystemTray.SetProgressIndicator(this, prog);
Deployment.Current.Dispatcher.BeginInvoke(() =>
{
btnWork.Visibility = Visibility.Collapsed;
tbMessage.Text = "Рабочий процесс запущен,
пожалуйста, подождите 5 секунд.";
});
RunProcessAsync(DateTime.Now);
}
/// <summary>
/// Запуск процесса
/// </summary>
/// <param name="dumpDate"></param>
public void RunProcessAsync(DateTime dumpDate)
{
//Новый фоновый рабочий процесс
BackgroundWorker worker = new BackgroundWorker();
//Подписка на событие завершения работы
worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted);
worker.DoWork += new DoWorkEventHandler(worker_DoWork);
worker.RunWorkerAsync(dumpDate);
}
/// <summary>
/// Обработчик события DoWork
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
async void worker_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = new BackgroundWorker();
// Здесь следует разместить код, выполняющий ресурсоёмкую задачу
Thread.Sleep(5 * 1000); // 5 секунд;
await worker.RunWorkerTaskAsync();
}
//Обработчик события завершения работы фонового процесса
void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
worker.RunWorkerCompleted -= new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted);
worker.DoWork -= new DoWorkEventHandler(worker_DoWork);
Deployment.Current.Dispatcher.BeginInvoke(() =>
{
tbMessage.Text = "Выполнение задачи завершено.";
btnWork.Visibility = Visibility.Visible;
});
SystemTray.ProgressIndicator.IsVisible = false;
}
//Добавлено, иллюстрация синхронного кода
private void btnSyncWork_Click(object sender, RoutedEventArgs e)
{
Storyboard1.Begin();
tbMessage.Text = "Выполнение задачи начато, пожалуйста, подождите 5 секунд.";
Thread.Sleep(5 * 1000);
tbMessage.Text = "Выполнение задачи завершено.";
}
}
}
Обратите внимание на место в методе worker_DoWork, где следует разместить ресурсоёмкий код. Здесь размещена команда Thread.Sleep(5*1000), которая позволяет заблокировать текущий поток на заданное количество миллисекунд, 5000 миллисекунд – это 5 секунд.
Для класса BackgroundWorker в рассматриваемом проекте определен метод расширения RunWorkerTaskAsync. Такие методы определяются как статические, при их определении указывается тип, с которым оперирует метод, вызов метода осуществляется для экземпляра класса – именно это происходит в вызове await worker.RunWorkerTaskAsync();. Код метода расположен в файле BackgroundWorkerExtensions, Листинг 43.3.
using System.ComponentModel;
using System.Threading.Tasks;
namespace CSWP8ProgressIndicator
{
//Задача для фонового процесса
public static class BackgroundWorkerExtensions
{
public static Task<object> RunWorkerTaskAsync(this BackgroundWorker backgroundWorker)
{
var tcs = new TaskCompletionSource<object>();
RunWorkerCompletedEventHandler handler = null;
handler = (sender, args) =>
{
if (args.Cancelled)
tcs.TrySetCanceled();
else if (args.Error != null)
tcs.TrySetException(args.Error);
else
tcs.TrySetResult(args.Result);
};
backgroundWorker.RunWorkerCompleted += handler;
try
{
backgroundWorker.RunWorkerAsync();
}
catch
{
backgroundWorker.RunWorkerCompleted -= handler;
throw;
}
return tcs.Task;
}
}
}
Для получения дополнительных сведений по использованию асинхронных методов и работе с потоками рекомендуется обратиться к материалам "Асинхронное программирование с использованием ключевых слов Async и Await" и "Работа с потоками" раздела "Основные понятия программирования", http://msdn.microsoft.com/ru-ru/library/dd460655.aspx, который посвящен особенностям работы в Visual Studio 2012.
В этой лабораторной работе мы рассмотрели особенности работы с асинхронным кодом. Использование такого кода позволяет при выполнении ресурсоёмких операция переложить вычислительную нагрузку на потоки, отличные от потока пользовательского интерфейса. В итоге, пользовательский интерфейс не блокируется, пользователь может взаимодействовать с приложением во время работы асинхронного кода.
Проанализируйте код приложения, которое вы разрабатываете, испытайте различные варианты работы с ним и рассмотрите возможность асинхронного исполнения участков кода, которые выполняют в потоке пользовательского интерфейса какие-либо ресурсоёмкие операции (например, обрабатывают большие массивы данных). Подготовьте отчёт, содержащий данные анализа кода приложения на предмет асинхронного выполнения, и, если это применимо к вашему приложению, примеры модифицированного кода.
К данной лекции подготовлено видеоприложение и демонстрационный программный проект.
Цель работы: освоить технологию работы с классом BackgroundWorker
Создавая простое приложение для Windows Phone, не выполняющее сложных вычислений, не обращающееся к веб-сервисам, не выполняющее работу с файлами, о выполнении каких-либо задач вне потока пользовательского интерфейса обычно не задумываются. Если мы, например, в обработчике события нажатия на кнопку захотим выполнить какое-то простое вычисление, или проверку какого-либо условия, вычислительная нагрузка от таких операций ляжет на поток пользовательского интерфейса. До тех пор, пока эта нагрузка незначительна, подобное не сказывается на скорости отклика приложения. Но если нужно выполнить какую-либо ресурсоёмкую операцию, это можно сделать и без дополнительных усилий по использованию для неё другого потока, однако, выполнение её в потоке пользовательского интерфейса приведет к заметным задержкам. Как вы увидите в примере, который мы разберем в этой лабораторной работе, интерфейс может быть блокирован. То есть, приложение не реагирует на взаимодействие пользователя с элементами управления, анимация может либо приостановиться, либо работать рывками.
В предыдущих лабораторных работах мы сталкивались с вызовом асинхронных методов для выполнения задач, которые могут занимать потенциально достаточно большое время. При объявлении метода, в котором мы вызывали асинхронные операции, используется модификатор async, операция вызывается с использованием оператора await. Это приводит к тому, что выполнение метода приостанавливается до тех пор, пока не будет получен ответ от вызываемой процедуры. Например – данные, загруженные с веб-сервера. При этом использование async и await упрощает написание асинхронного кода, так как до появления этого механизма (это произошло в Visual Studio 2012) при вызове асинхронного метода нужно было предусматривать использование функции, которая вызывается при завершении работы метода и обрабатывает полученные результаты. Такой подход применим и сейчас, но он усложняет структуру кода, в то время как асинхронный код, написанный с использованием async и await, хотя и решает задачи асинхронной обработки, выглядит как синхронный.
До сих пор мы вызывали асинхронные методы каких-либо объектов, но нередко возникают задачи, для успешного решения которых нужно асинхронно выполнить произвольный код. То есть, выполнить этот код не в потоке пользовательского интерфейса, а в другом потоке. При таком подходе интерфейс продолжает реагировать на воздействия пользователя. Решить подобную задачу можно, например, с использованием класса ).
Он предоставляет средства для выполнения операций в потоках, отличных от потока пользовательского интерфейса. Рассмотрим пример, иллюстрирующий работу с BackgroundWorker.
В основу этого примера положен пример "Work with ProgressIndicator and hide", http://code.msdn.microsoft.com/Work-with-ProgressIndicator-545eb39d. Здесь представлен русифицированный код, снабжённый дополнительными комментариями и дополнениями, иллюстрирующими недостатки синхронного выполнения задач, аналогичных тем, которые решаются с помощью выполнения задач в потоке, отличном от потока пользовательского интерфейса. В частности, здесь к исходному коду, добавлена демонстрация того, как выполнение ресурсоёмкой задачи в потоке пользовательского интерфейса блокирует анимацию, делает невозможной нормальную работу с элементами управления пользовательского интерфейса. Рекомендуется при освоении этого примера загрузить его по указанной ссылке, так как в него могут быть внесены дополнения и обновления, а код, приведенный здесь, использовать как справочное руководство.
В исходном примере так же показана работа с индикатором выполнения, который сигнализирует пользователю о том, что в настоящий момент выполняется какая-либо ресурсоёмкая задача. В подобных задачах такой подход весьма актуален, так как пользователю нужно сообщать о том, что приложение выполняет какую-то ресурсоёмкую задачу и пользователю, для выполнения результатов, следует некоторое время подождать. При этом весьма желательно указывать время, которое может занять выполнение задачи. В нашем случае мы искусственно создаём 5-секундную задержку, которая имитирует сложную вычислительную задачу. В реальных условиях, если неизвестно точно, сколько времени будет выполняться операция, экспериментальным путём можно выяснить хотя бы приблизительное время и сообщить об этом пользователю.
На рис. 22.1. вы можете видеть окно проекта.
(рис 43.1) Окно проекта
На главной странице (Листинг 43.1) присутствуют кнопки Выполнить асинхронно и Выполнить синхронно, запускающие выполнение имитации ресурсоёмкой задачи, на выполнение которой нужно 5 секунд, соответственно, асинхронно, в дополнительном потоке, и синхронно, в потоке пользовательского интерфейса. Прямоугольник на странице анимирован – для демонстрации того, как синхронное выполнение ресурсоёмких задач влияет на пользовательский интерфейс. Флаг Проверьте отклик интерфейса позволяет проверить реакцию интерфейса в ходе синхронного и асинхронного выполнения задачи.
<phone:PhoneApplicationPage
x:Class="CSWP8ProgressIndicator.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
FontSize="{StaticResource PhoneFontSizeNormal}"
Foreground="{StaticResource PhoneForegroundBrush}"
SupportedOrientations="Portrait" Orientation="Portrait"
shell:SystemTray.IsVisible="True">
<phone:PhoneApplicationPage.Resources>
<Storyboard x:Name="Storyboard1">
<ColorAnimationUsingKeyFrames Storyboard.TargetProperty="(Shape.Fill).
(SolidColorBrush.Color)" Storyboard.TargetName="rectangle">
<EasingColorKeyFrame KeyTime="0" Value="#FF1A1AEA"/>
<EasingColorKeyFrame KeyTime="0:0:5" Value="#FFEA1A1A"/>
</ColorAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).
(CompositeTransform.Rotation)" Storyboard.TargetName="rectangle">
<EasingDoubleKeyFrame KeyTime="0" Value="0"/>
<EasingDoubleKeyFrame KeyTime="0:0:5" Value="359.926"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</phone:PhoneApplicationPage.Resources>
<!--LayoutRoot is the root grid where all page content is placed-->
<Grid x:Name="LayoutRoot" Background="Transparent">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<!--TitlePanel contains the name of the application and page title-->
<StackPanel x:Name="TitlePanel" Grid.Row="0"
Margin="12,17,0,28">
<TextBlock Text="АСИНХРОННЫЙ КОД" Style="{StaticResource PhoneTextNormalStyle}" Margin="12,0"/>
<TextBlock Text="главная" Margin="9,-7,0,0"
Style="{StaticResource PhoneTextTitle1Style}"/>
</StackPanel>
<!--ContentPanel - place additional content here-->
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
<TextBlock x:Name="tbMessage"
Text="Нажмите на кнопку "Выполнить асинхронно" для начала выполнения фонового процесса.
Вы увидите идикатор выполнения. Когда задача будет завершена. индикатор будет скрыт,
будет выведено сообщение о завершении работы.
Нажмите на кнопку "Выполнить синхронно" для демонстрации синхронного выполнения
ресурсоёмкой задачи." TextWrapping="Wrap" ScrollViewer.VerticalScrollBarVisibility="Visible"/>
<Button x:Name="btnWork" Content="Выполнить асинхронно" HorizontalAlignment="Left" Margin="83,294,0,0"
VerticalAlignment="Top" Click="btnWork_Click"/>
<Rectangle x:Name="rectangle" Fill="#FFF4F4F5"
HorizontalAlignment="Left" Height="100" Margin="173,477,0,0"
Stroke="Black" VerticalAlignment="Top" Width="100"
RenderTransformOrigin="0.5,0.5">
<Rectangle.RenderTransform>
<CompositeTransform/>
</Rectangle.RenderTransform>
</Rectangle>
<Button x:Name="btnSyncWork" Content="Выполнить синхронно"
HorizontalAlignment="Left" Margin="83,374,0,0" VerticalAlignment="Top"
Click="btnSyncWork_Click" Width="305"/>
<CheckBox Content="Проверьте отклик интерфейса"
HorizontalAlignment="Left" Margin="10,222,0,0"
VerticalAlignment="Top"/>
</Grid>
</Grid>
</phone:PhoneApplicationPage>
В коде файла MainPage.xaml.cs (Листинг 2) показана работа синхронных механизмов (обработчик нажатия на кнопку btnSyncWork и асинхронных (их запуск производится при нажатии на кнопку btnWork.
using System;
using System.Windows;
using Microsoft.Phone.Controls;
using Microsoft.Phone.Shell;
using System.ComponentModel;
using System.Threading;
namespace CSWP8ProgressIndicator
{
public partial class MainPage : PhoneApplicationPage
{
static string strMsg = string.Empty; // Сообщение о результате.
// Конструктор
public MainPage()
{
InitializeComponent();
}
private void btnWork_Click(object sender, RoutedEventArgs e)
{
//Добавлено, воспроизведение анимации
Storyboard1.Begin();
// Создание и настройка нового индикатора выполнения
ProgressIndicator prog = new ProgressIndicator();
prog.IsVisible = true;
prog.IsIndeterminate = true;
prog.Text = "Выполнение задачи...";
//Установка нового индикатора
SystemTray.SetProgressIndicator(this, prog);
Deployment.Current.Dispatcher.BeginInvoke(() =>
{
btnWork.Visibility = Visibility.Collapsed;
tbMessage.Text = "Рабочий процесс запущен,
пожалуйста, подождите 5 секунд.";
});
RunProcessAsync(DateTime.Now);
}
/// <summary>
/// Запуск процесса
/// </summary>
/// <param name="dumpDate"></param>
public void RunProcessAsync(DateTime dumpDate)
{
//Новый фоновый рабочий процесс
BackgroundWorker worker = new BackgroundWorker();
//Подписка на событие завершения работы
worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted);
worker.DoWork += new DoWorkEventHandler(worker_DoWork);
worker.RunWorkerAsync(dumpDate);
}
/// <summary>
/// Обработчик события DoWork
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
async void worker_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = new BackgroundWorker();
// Здесь следует разместить код, выполняющий ресурсоёмкую задачу
Thread.Sleep(5 * 1000); // 5 секунд;
await worker.RunWorkerTaskAsync();
}
//Обработчик события завершения работы фонового процесса
void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
worker.RunWorkerCompleted -= new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted);
worker.DoWork -= new DoWorkEventHandler(worker_DoWork);
Deployment.Current.Dispatcher.BeginInvoke(() =>
{
tbMessage.Text = "Выполнение задачи завершено.";
btnWork.Visibility = Visibility.Visible;
});
SystemTray.ProgressIndicator.IsVisible = false;
}
//Добавлено, иллюстрация синхронного кода
private void btnSyncWork_Click(object sender, RoutedEventArgs e)
{
Storyboard1.Begin();
tbMessage.Text = "Выполнение задачи начато, пожалуйста, подождите 5 секунд.";
Thread.Sleep(5 * 1000);
tbMessage.Text = "Выполнение задачи завершено.";
}
}
}
Обратите внимание на место в методе worker_DoWork, где следует разместить ресурсоёмкий код. Здесь размещена команда Thread.Sleep(5*1000), которая позволяет заблокировать текущий поток на заданное количество миллисекунд, 5000 миллисекунд – это 5 секунд.
Для класса BackgroundWorker в рассматриваемом проекте определен метод расширения RunWorkerTaskAsync. Такие методы определяются как статические, при их определении указывается тип, с которым оперирует метод, вызов метода осуществляется для экземпляра класса – именно это происходит в вызове await worker.RunWorkerTaskAsync();. Код метода расположен в файле BackgroundWorkerExtensions, Листинг 43.3.
using System.ComponentModel;
using System.Threading.Tasks;
namespace CSWP8ProgressIndicator
{
//Задача для фонового процесса
public static class BackgroundWorkerExtensions
{
public static Task<object> RunWorkerTaskAsync(this BackgroundWorker backgroundWorker)
{
var tcs = new TaskCompletionSource<object>();
RunWorkerCompletedEventHandler handler = null;
handler = (sender, args) =>
{
if (args.Cancelled)
tcs.TrySetCanceled();
else if (args.Error != null)
tcs.TrySetException(args.Error);
else
tcs.TrySetResult(args.Result);
};
backgroundWorker.RunWorkerCompleted += handler;
try
{
backgroundWorker.RunWorkerAsync();
}
catch
{
backgroundWorker.RunWorkerCompleted -= handler;
throw;
}
return tcs.Task;
}
}
}
Для получения дополнительных сведений по использованию асинхронных методов и работе с потоками рекомендуется обратиться к материалам "Асинхронное программирование с использованием ключевых слов Async и Await" и "Работа с потоками" раздела "Основные понятия программирования", http://msdn.microsoft.com/ru-ru/library/dd460655.aspx, который посвящен особенностям работы в Visual Studio 2012.
В этой лабораторной работе мы рассмотрели особенности работы с асинхронным кодом. Использование такого кода позволяет при выполнении ресурсоёмких операция переложить вычислительную нагрузку на потоки, отличные от потока пользовательского интерфейса. В итоге, пользовательский интерфейс не блокируется, пользователь может взаимодействовать с приложением во время работы асинхронного кода.
Проанализируйте код приложения, которое вы разрабатываете, испытайте различные варианты работы с ним и рассмотрите возможность асинхронного исполнения участков кода, которые выполняют в потоке пользовательского интерфейса какие-либо ресурсоёмкие операции (например, обрабатывают большие массивы данных). Подготовьте отчёт, содержащий данные анализа кода приложения на предмет асинхронного выполнения, и, если это применимо к вашему приложению, примеры модифицированного кода.
К данной лекции подготовлено видеоприложение и демонстрационный программный проект.
Для получения официальных документов о завершении программы дополнительного профессионального образования (удостоверения о повышении квалификации, дипломов о профессиональной переподготовке и MBA) необходимо предоставить:
Внимание! Вы можете не заказывать доставку бумажной версии официального документы, а скачать его в электронном виде и распечатать самостоятельно. Информация о выданном документе в течение 1 месяца загружается в Федеральную информационную систему «Федеральный реестр сведений о документах об образовании и (или) о квалификации, документах об обучении» - ФИС ФРДО.
Доступ на новый сайт осуществляется с использованием адреса электронной почты, который был указан вами при регистрации на "старом". Мы постарались перенести все ваши данные с прежнего ресурса, однако не исключена вероятность потери части информации.
При возникновении проблемы со входом, воспользуйтесь функцией сброса пароля
Если вы обнаружите несоответствия, пожалуйста, сообщите нам.