При нажатии на Сумма в примере 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).