Механизм привязки данных (DataBinding), страница 17

Как и со многими другими классами .NET, работать с работником — одно удовольствие. Надо лишь сказать, что ему делать после того, как он получит команду: "Приступай", и как вести себя по окончании работы. Первое действие представляет собой подписку на событие DoWork (создание делегата). Это выглядит так.

ordersWorker.DoWork += new DoWorkEventHandler (ordersWorker_DoWork);

Само событие DoWork будет сгенерировано лишь после того, как работник получит команду приступить к работе. Такой командой является вызов метода RunWorkerAsync. Это выглядит так.

ordersWorker.RunWorkerAsync ((string) row["CustomerID"]);

Смотрите, здесь неясно, что делать, но ясно, что получить в качестве входного параметра. Далее в работу включается операционная система. Она генерирует событие DoWork, вызывает задание делегата, в котором мы вызываем метод GetOrders. Это выглядит так.

void ordersWorker_DoWork (object sender, DoWorkEventArgs e)

{

e.Result = GetOrders (e.Argument.ToString ());

}

Здесь уже ясно, что делать и куда поместить результат. В этот момент система запускает другой поток, который выполняет (асинхронно) наш метод GetOrders. Заметьте, что идентификатор клиента (CustomerID), необходимый для выполнения задания, сгенерирован и передан нам системой (вместе с событием DoWork). Он спрятан в рамках объекта DoWorkEventArgs и выглядит, как e.Argument.

По завершении метода GetOrders генерируется событие RunWorkerCompleted. Мы должны ввести в класс формы функцию его обработки, в теле которой можно получить результат, опять же из параметра, генерируемого системой.

void ordersWorker_RunWorkerCompleted (object sender, RunWorkerCompletedEventArgs e)

{

ordersSource.DataSource = e.Result;

}

Синхронизатор позиции таблицы заказов ordersSource получает желаемое подмножество строк (отфильтрованный DataView) и это заставляет DataGridView, которым управляет ordersSource, отобразить искомые заказы. Итак, основная логика управления работником ясна, но к ней следует добавить логику управления элементом progressBar и курсором ожидания. С помощью этих элементов имитируется ситуация длительного ожидания при обращении к Web-сервису. Все вместе выглядит так.

¨  Оставьте без изменений метод ordersWorker_DoWork.

¨  В реакцию на загрузку формы добавьте вызов метода, создающего BackgroundWorker.

private void MainForm_Load (object sender, EventArgs e)

{

SetBinding();

FillDictionary();

SetBackgroundWorker();

customersSource.Position = 0;

customersSource_CurrentChanged (customersSource, EventArgs.Empty);

}

¨  Полностью замените метод, обрабатывающий событие CurrentChanged, которое генерирует синхронизатор.

void customersSource_CurrentChanged (object sender, EventArgs e)

{

DataRowView row = customersSource.Current as DataRowView;

if (row != null) // Синхронизация картинки с флагом

{

string country = (string)row["Country"];

if (flags.ContainsKey(country))

pic.Image = flags[country];

ordersSource.DataSource = null;  // Сотрем старые заказы

UseWaitCursor = true;

ShowProgress (true);

ordersWorker.RunWorkerAsync ((string) row["CustomerID"]); // Генерируем событие DoWork

}

}

¨  Введите в состав класса формы метод, создающий и настраивающий объект класса BackgroundWorker.

private void SetBackgroundWorker () // Единократное создание работника

{

ordersWorker = new BackgroundWorker ();

ordersWorker.DoWork += new DoWorkEventHandler (ordersWorker_DoWork);

ordersWorker.RunWorkerCompleted +=

new RunWorkerCompletedEventHandler (ordersWorker_RunWorkerCompleted);

timer = new System.Windows.Forms.Timer ();

timer.Interval = 100;

timer.Tick += new EventHandler (timer_Tick);

}

¨  Введите метод, управляющий таймером и индикатором прогресса.

private void ShowProgress (bool start)

{

if (start)

timer.Start();

else

timer.Stop();

progressBar.Visible = start;

progressBar.Value = 0;

}

¨  Введите метод, реагирующий на событие истечения кванта времени таймера. Здесь мы продвигаем вперед индикатор прогресса (изменяем его позицию — свойство Value).

void timer_Tick (object sender, EventArgs e) { progressBar.PerformStep(); }