Ни вариант .NET Framework для настольных компьютеров, ни вариант .NET Compact Framework для мобильных устройств не поддерживают доступ к большинству свойств и методов элементов пользовательского интерфейса из потоков, которым они не принадлежат. Хотя такой код и будет нормально компилироваться, результаты его выполнения будут непредсказуемыми. Для обеспечения межпоточных вызовов в .NET Framework и .NET Compact Framework поддерживается метод Control.Invoke(). В версии 1.1 .NET Compact Framework поддерживается лишь использование механизма Control.Invoke() для вызова функций без параметров. Более подробную информацию относительно применения этого метода вы найдете в справочной документации MSDN. Не составляет труда организовать на приемлемом уровне обмен данными между фоновым потоком и потоком пользовательского интерфейса, предусмотрев для этого выполняющийся в потоке пользовательского интерфейса код, который периодически опрашивает объект, специально предназначенный для управления выполнением фоновых потоков, с целью определения того, имеются ли данные, ожидающие реакции пользовательского интерфейса. Обычно сделать это гораздо проще, чем погружаться во все тонкости межпоточного вызова методов.
Второй подход связан с использованием косвенно вызываемого делегата, указывающего на функцию формы вашего приложения. В качестве такой функции (не имеющей параметров — см. выше) может быть назначена функция класса формы, которую можно вызвать посредством метода Invoke() формы. Вызов Invoke() приведет к выполнению упомянутой функции в потоке пользовательского интерфейса. После этого функция может извлечь любые необходимые данные и соответствующим образом обновить пользовательский интерфейс. Достоинством такого подхода является то, что высокоприоритетный поток не должен выполнять цикл опроса и получает обновленную информацию сразу же после завершения фоновой работы. Недостаток этого подхода заключается в том, что он требует создания (предположительно, на очень короткое время) синхронной связи между фоновым и высокоприоритетным потоками выполнения. Когда делегат запускается на выполнение в фоновом потоке, выполнение фонового потока приостанавливается, контекст выполнения переключается на высокоприоритетный поток, и делегат начинает выполняться. Это препятствует переключению фонового потока на выполнение другой работы, находящейся в очереди. Выполнение фонового потока сможет возобновиться лишь после того, как выполнение делегата завершится.
Пример использования фоновой обработки одновременно с обновлением данных высокоприоритетного потока пользовательского интерфейса
Сейчас мы вернемся к нашему примеру с простыми числами, который рассматривался в главе 5, заметно изменив и усовершенствовав его. На этот раз мы создадим приложение типа SmartPhone, вычисляющее простые числа большой величины. Во время проведения большого объема вычислений фоновым потоком приложение будет сохранять способность к интерактивному взаимодействию с пользователем. Приложение предоставляет пользователю возможность при необходимости прекратить выполнение фонового потока. Кроме того, и это немаловажно, в приложении реализован неплохой способ информирования пользователя о состоянии выполнения интересующей его задачи. Зная, что фоновая задача успешно выполняется, пользователь будет чувствовать себя более комфортно
Данное приложение несложно адаптировать для выполнения на Pocket PC. Наш выбор Microsoft Smartphone в качестве целевой платформы был сделан исключительно в интересах разнообразия.
Рис. 9.2. Окно интегрированной среды разработки Visual Studio, предcтавляющее проектируемый пользовательский интерфейс приложения типа Smartphone
Рис. 9.3. Экранные снимки эмулятора Smartphone, полученные в процессе вычисления приложением простых чисел
НА ЗАМЕТКУ
Если вы используете Visual Studio .NET 2003, то вам необходимо загрузить SDK для Windows Mobile 2003-based Smartphones. Visual Studio NET 2003 поставлялась с "коробочным" вариантом средств разработки приложений для Pocket PC, но не для Smartphone. Поскольку SDK для Smartphone поставлялся после выхода Visual Studio .NET 2003, его следует загрузить и установить поверх Visual Studio .NET. Пакет SDK можно бесплатно загрузить с Web- сайта компании Microsoft (см. приложение А). Этот SDK включает в себя компоненты, необходимые для проектирования пользовательских интерфейсов Smartphone, а также эмулятор Smartphone, позволяющий выполнять приложения, даже если вы не располагаете физическим устройством Smartphone.
Чтобы создать и запустить указанное приложение, выполните следующие действия:
1. Запустите Visual Studio .NET (2003 или более позднюю версию) и создайте проект C# Smart Device Application.
2. Выберите в качестве целевой платформы Smartphone. (Для вас будет автоматически создан проект, и на экране появится конструктор форм для Smartphone.)
3. Используя рис. 9.2 в качестве образца для компоновки формы, добавьте в нее следующие элементы управления:
• TextBox (textBox1); задайте в качестве значения свойства Text длинную текстовую строку (например, 12345678901234).
• Label (label1); измените размеры элемента управления Label таким образом, чтобы он занимал большую часть области формы. В нем придется отображать текст, состоящий из нескольких строк.
• Timer (timer1).
4. Выделите компонент MainMenu в нижней части окна конструктора форм и добавьте следующие пункты меню:
• Перейдите к крайнему слева меню (содержащему текст "Type Here" ("Набирайте здесь")) и введите Exit в качестве текста меню. Используя окно Properties, измените имя элемента меню с menuItem1 на menuItemExit.
• Справа от меню Exit, которое вы только что добавили (там, где находится текст "Type Here"), введите Prime Search в качестве текста меню. Примечание: при необходимости обратитесь к рис. 9.2.
• Над меню Prime Search, которое вы только что добавили (там, где находится текст "Type Here"), введите Start в качестве текста меню. Используя окно Properties, измените имя элемента меню с menuItem2 на menuItemStart. Примечание: при необходимости обратитесь к рис. 9.2.
• Ниже меню Start, которое вы только что добавили (там, где находится текст "Type Here"), введите Abort в качестве текста меню. Используя окно Properties, измените имя элемента меню с menuItem2 на menuItemStart. Примечание: при необходимости обратитесь к рис. 9.2.
5. Добавьте в проект новый класс. Назовите его FindNextPrimeNumber.сs. Замените содержимое кода класса в окне редактора кодом из листинга 9.5.
6. Перейдите обратно в окно Form1.cs [Design] и дважды щелкните на элементе меню Exit. В результате этого будет автоматически сгенерирована функция void menuItemExit_Click(), а фокус переместится в окно редактора кода. Введите для этой функции код из листинга 9.4.
7. Перейдите обратно в окно Form1.cs [Design] и дважды щелкните на элементе меню Start. В результате этого будет автоматически сгенерирована функция private void menuItemStart_Click(), а фокус переместится в окно редактора кода. Введите для этой функции код из листинга 9.4.
8. Перейдите обратно в окно Form1.cs [Design] и дважды щелкните на названии меню Abort. В результате этого будет автоматически сгенерирована функция private void menuItemAbort_Click(), а фокус переместится в окно редактора кода. Введите для этой функции код из листинга 9.4.
9. Перейдите обратно в окно Form1.CS [Design] и дважды щелкните на элементе управления timer1 в нижней части окна конструктора. В результате этого будет автоматически сгенерирована функция private void timer1_Tick(). Введите для этой функции код из листинга 9.4.