|
При нажатии на Сумма в примере ArbitraryMethod из Лекция 7, VS 2013 выдается ошибка: Необработанное исключение типа "System.InvalidOperationException" в System.Windows.Forms.dll Дополнительные сведения: Недопустимая операция в нескольких потоках: попытка доступа к элементу управления "lblResult" не из того потока, в котором он был создан. Затем: Необработанное исключение типа "System.InvalidOperationException" в mscorlib.dll Дополнительные сведения: Для каждой асинхронной операции метод EndInvoke может вызываться только один раз. |
Асинхронное программирование
Асинхронный запуск произвольного метода
При разработке программного обеспечения наиболее часто требуется запускать асинхронно собственные методы. Для этого нужно проделать следующие шаги:
- Создать и запустить делегат с необходимой сигнатурой. После этого можно работать со своим методом так же, как и с методами со встроенной поддержкой асинхронной модели программирования.
- Выбрать механизм оповещения о завершении и подготовить для него все необходимое.
- Запустить метод асинхронно.
- Получить результаты в основном потоке и обновить пользовательский интерфейс.
Создайте новое Windows-приложение и назовите его ArbitraryMethod. Добавляем на форму три надписи, два текстовых поля и одну кнопку, и устанавливаем им следующие свойства:
Устанавливаем свойству Size формы значение 424; 144 и заголовок "Асинхронный запуск произвольного метода". Переходим в код формы. Создание делегата в данном случае ничем не отличается от общих правил, рассмотренных в "Введение в windows-формы" :
// Делегат, принимающий две переменные типа int и возвращающий одну переменную типа int, // для асинхронного запуска метода (Summ) private delegate int AsyncSumm(int a, int b);Листинг 7.4.
Создаем метод Summ, в котором будут складываться числа, вводимые в два текстовых поля:
private int Summ(int a, int b)
{
return a+b;
}Обработчик кнопки btnRun будет выглядеть следующим образом:
private void btnRun_Click(object sender, System.EventArgs e)
{
int a, b;
try
{
// Преобразование типов данных.
a = Int32.Parse(txbA.Text);
b = Int32.Parse(txbB.Text);
}
catch(Exception)
{
MessageBox.Show("При выполнении преобразования типов возникла ошибка");
txbA.Text = txbB.Text = "";
return;
}
AsyncSumm summdelegate = new AsyncSumm(Summ);
AsyncCallback cb = new AsyncCallback(CallBackMethod);
summdelegate.BeginInvoke(a, b, cb, summdelegate);
}
Листинг
7.5.
Мы создали экземпляр summdelegate делегата AsyncSumm и проинициализировали его методом Summ:
AsyncSumm summdelegate = new AsyncSumm(Summ);
Для использования механизма Сallback создали экземпляр делегата AsyncCallBack:
AsyncCallback cb = new AsyncCallback(CallBackMethod);
Метод CallBackMethod имеет сигнатуру, принимающую один параметр типа IAsyncResult и не возвращающую значений. После того как делегат инициализирован методом, можно запускать прикрепленный к делегату метод асинхронно с помощью метода BeginInvoke. Этот метод принимает две переменные типа int а и b, экземпляр cb делегата AsyncCallback и экземпляр summdelegate делегата SummDelegate:
summdelegate.BeginInvoke(a, b, cb, summdelegate);
Создаем метод CallBackMethod, который привязан к делагату summdelegate:
private void CallBackMethod(IAsyncResult ar)
{
AsyncSumm summdelegate = (AsyncSumm)ar.AsyncState;
lblResult.Text = String.Format("Сумма введенных чисел равна {0}", summdelegate.EndInvoke(ar));
}
Листинг
7.6.
Этот метод запустится после завершения работы метода, запущенного асинхронно. В его теле также запускаем метод EndInvoke для получения результата.
При запуске приложения после ввода чисел и нажатия кнопки "Сумма" метод EndInvoke возвращает результат в надпись (рис. 7.3).
На диске, прилагаемом к книге, вы найдете приложение ArbitraryMethod (Code\Glava7\ ArbitraryMethod).
