Модель STA

135

Как известно платформа WPF коренным образом изменила почти все основы программирования для Windows. Она предложила новый подход ко всему — от определения содержимого окна до отображения трехмерной графики. Платформа WPF даже представила новые концепции, которые не являются очевидным образом сосредоточенными на пользовательском интерфейсе, такие как свойства зависимости и маршрутизируемые события.

Разумеется, огромное количество задач кодирования выходят за рамки программирования пользовательского интерфейса, а потому они не подверглись изменениям в мире WPF. Например, приложения WPF используют те же классы, что и другие приложения .NET, при подключении к базам данных, манипуляциях с файлами и проведении диагностики.

Также несколько средств попадают в область, лежащую где-то между традиционным программированием .NET и WPF. Эти средства не ограничены строго рамками WPF-приложений, но имеют некоторые специфичные для WPF особенности. Примером может служить модель дополнений (add-in model), которая позволяет WPF-приложению динамически загружать и использовать отдельно скомпилированные компоненты с полезными порциями функциональности. Многопоточность позволяет WPF-приложению выполнять фоновую работу, сохраняя пользовательский интерфейс максимально отзывчивым.

Многопоточность

Многопоточность — это искусство выполнения более чем одного фрагмента кода одновременно. Целью многопоточности обычно является создание более отзывчивого интерфейса — такого, который не "замораживается" во время работы, — хотя многопоточность можно применять также и для того, чтобы полнее задействовать преимущества двухядерного процессора при выполнении ресурсоемких алгоритмов или другой работы одновременно с некоторой длительной операцией (например, чтобы выполнять некоторые вычисления в процессе ожидания ответа от веб-службы).

В самом начале проектирования платформы WPF ее разработчики предусмотрели новую модель многопоточности. Эта модель, называемая арендой потоков (thread rental), позволила обращаться к объектам пользовательского интерфейса из любого потока. Чтобы сократить стоимость блокировки, группы взаимосвязанных объектов могут объединяться под одной блокировкой (называемой контекстом). К сожалению, такое проектное решение усложнило однопоточные приложения (которые должны учитывать контекст) и затруднило взаимодействие с унаследованным кодом (вроде Win32 API).

В конечном итоге от этого подхода пришлось отказаться. В результате теперь WPF поддерживает модель однопоточного апартамента (single-threaded apartment — STA), которая очень похожа на ту, что используется в приложениях Windows Forms. С этой моделью связано несколько основных правил:

Диспетчер

Диспетчер управляет работой, происходящей в WPF-приложении. Диспетчер владеет потоком приложения и управляет очередью элементов работы. Во время работы приложения диспетчер принимает новые запросы работы и выполняет их по одному.

Формально диспетчер создается при первоначальном создании в новом потоке экземпляра класса, который наследуется от DispatcherObject. В случае создания отдельных потоков и использования их для отображения отдельных окон получается более одного диспетчера. Однако большинство приложений не усложняют картину и обходятся одним потоком пользовательского интерфейса и одним диспетчером. Затем они используют многопоточность для управления операциями с данными и другими фоновыми задачами.

Диспетчер — это экземпляр класса System.Windows.Threading.Dispatcher. Все связанные с диспетчером объекты также находятся в пространстве имен System.Windows.Threading, которое является новым в WPF. (Центральные классы для организации потоков, которые существуют со времен .NET 1.0, находятся в пространстве System.Threading.)

Получить диспетчер для текущего потока можно через статическое свойство Dispatcher.CurrentDispatcher. Используя объект Dispatcher, можно присоединить обработчики событий, которые отвечают за необработанные исключения или реагируют на завершение диспетчера. Можно также получить ссылку на поток System.Threading.Thread, которым управляет диспетчер, завершить диспетчер или направить код на выполнение правильному потоку.

Лучший чат для C# программистов