Начинаем цикл публикаций, призванных помочь начинающим программистам в создании контекстно-зависимых приложений для Windows 7. Об этом много говорили на PDC да и мы неоднократно писали о этом новом классе приложений. Пользователи Windows 7 build 6801 могли заметить появление в гаджете погоды опции автоматического определения местоположения компьютера. И сегодня у вас появилась уникальная возможность попробовать себя в создании подобных приложений.
Я решил немного поиграть с Windows Location Platform, входящей в состав Windows 7 build 6801, которая была роздана посетителям конференции PDC 2008, и решил попробовать создать свое WPF-приложение, которое показывало бы карту Virtual Earth и мое местоположение на ней.
В сборке 6801 всем СОМ-классы Location API обозначены как ThreadingModel = Free (MTA). Поэтому, для того чтобы вызвать их из другой потоковой модели (STA), придется прибегнуть к промежуточным классам. Похоже, что сборка, генерируемая VS (LocationDispLib.dll), не включает в себя эти самые промежуточные классы для COM-распределения. Таким образом, для получения доступа к Location API нам необходимо использовать другой поток, который позволит использовать эти данные в нашем WPF-приложении.
Сценарии, которые позволяет реализовать приложение
Показывать карту на базе местоположения пользователя
Показывать схему движения, автоматически обновляя данные
Очищать карту
Запускаем приложение.
Нажимаем на кнопку Show Me on Map, Windows Location Platform получает координаты, приложение отмечает текущее местоположение на карте.
Приложение отслеживает перемещения и ежесекундно отмечает их.
Как это реализовано
Windows Location Platform API представлены COM- и Win32-объектами. Для упрощения программирования мы воспользуемся COM-версией API, которая внедрена в файл LocationDisp.dll в папке %Windir%\System32\ (в x86-версии). Для использования данного API нам необходимо добавить в проект ссылку на эту библиотеку.
1. Так как API запускаются в режиме MTA, а основное WPF-приложение в STA, нам нужно использовать отдельный поток для того, чтобы наше приложение могло получить информацию от API.
BackgroundWorker m_worker предназначен для обработки изменения местоположения, а второй BackgroundWorker m_workerStatus добавляем в определение Window1:
BackgroundWorker m_worker = new BackgroundWorker();
BackgroundWorker m_workerStatus = new
BackgroundWorker();
private LatLongReport m_report = new LatLongReport();
private LocationPlatformStatus m_status = new LocationPlatformStatus();
DispatcherTimer m_timerAutoTracking = new DispatcherTimer();
DispatcherTimer m_timerLocPlatformStatus = new DispatcherTimer();
bool m_useAutoTracking = false;
Таймеры будут использоваться для обработки изменения местоположения (m_timerAutoTracking). LatLongReport - .NET упаковщик для класса DispLatLongReport из Interop.LocationDisp.dll, которая была создана из LocationDisp.dll силами Visual Studio. Она необходима для того, чтобы несколько упростить COM-функцию, вызываемую в .NET-приложении.
В конструкторе Window1 мы инициализируем и фоновые исполнители, и таймеры:
public Window1()
{
InitializeComponent();
m_worker.DoWork += new DoWorkEventHandler(worker_DoWork);
m_worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted);
m_workerStatus.DoWork += new DoWorkEventHandler(m_workerStatus_DoWork);
m_workerStatus.RunWorkerCompleted += new RunWorkerCompletedEventHandler
(m_workerStatus_RunWorkerCompleted);
m_timerAutoTracking.Interval = new TimeSpan(0, 0, 0, 0, 1000);
m_timerAutoTracking.Tick += new EventHandler(m_timer_Tick);
m_timerLocPlatformStatus.Interval = new TimeSpan(0, 0, 0, 0, 1000);
m_timerLocPlatformStatus.Tick += new EventHandler(m_timerLocPlatformStatus_Tick);
// enabling Status Timer
m_timerLocPlatformStatus.Start();
}
Здесь мы просто инициализировали асинхронные обработчики событий DoWork и RunWorkerCompleted для обоих исполнителей Background Worker, настров интервал в 1 секунду для таймеров и обработчиков их событий.
Вызов Windows Location Platform API
Нажав кнопку Show Me On Map, пользователь инициализирует в приложении соответствующую команду и она запускает асинхронный исполнитель Background Worker m_worker:
public void ShowMeOnMapCommand_Executed(object sender, ExecutedRoutedEventArgs e)
{
try
{ m_worker.RunWorkerAsync();
} catch
{
// some times it can't do the job at 1 sec
}
}
Тут, однако, есть маленькая проблема. Так как мы не подписываемся на события через Location API, но при этом вызываем их, используя таймеры, исполнители Background Worker могут столкнуться с проблемой, при которой они не успели завершить свою работу. Чтобы не усложнять приложение, я решил добавить здесь блок.
RunWorkerAsync() включает событие DoWork() из фонового исполнителя m_worker:
void worker_DoWork(object sender, DoWorkEventArgs e)
{
LatLongReportFactoryClass factory = new LatLongReportFactoryClass();
m_report = new LatLongReport(factory.LatLongReport);
}
Именно здесь происходит реальное обращение к Windows Location API. То есть нам необходимо сослаться на LatLongReportFactoryClass и получить от него LatLongReport, который и будет использоваться в приложении. В действительности, первое, что нам необходимо сделать - проверить поле LatLongFactoryClass.Status, чтобы убедится, что сенсоры доступны и работают.
Когда фоновый исполнитель m_worker завершит получение LatLongReport, нам нужно создать на карте новый PushPin, дать ему текущие координаты и показать на карте.
void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Cancelled)
{
//Cancelled
}
else if (e.Error != null)
{
//Exception Thrown }
else
{
//Completed
PushPin pushPin = new PushPin();
pushPin.Latitude = m_report.Latitude;
pushPin.Longitude = m_report.Longitude; t
his.VirtualEarth.PushPins.Add(pushPin);
pushPin.CenterInMap();
}
}
В данном методе мы центрируем карту, чтобы созданная отметка показывалась по центру Virtual Earth. В случае если сенсоры присутствуют, включены и доступны, нажатие кнопки Show Me on Map покажет в центре карты Virtual Earth нашу позицию.
2. Для реализации автоматического обновления местоположения мы используем таймер Dispatcher Timer m_timer, который автоматически будет запускать Background Worker m_worker для получения информации о местоположении.
Для этого мы просто добавим в обработчик вызова кнопки Show/Stop showing My Trip on Map Automatically вызов Start/Stop m_timer, а для отметки на карте - m_worker.RunWorkerA.
3. Чтобы очистить карту, требуется вызвать метод “Clear” из коллекции контролов “PushPins”.
Теперь вы знаете, как вызывать Windows 7 Location Platform API с целью получить информацию о местоположении пользователя, и использовать ее в WPF-приложении.
Вот, собственно, и все. В следующий раз мы поговорим о том, как проверить статус платформы, о том, что делать в случае, если доступ запрещен, и что делать с провайдером, используемым по умолчанию.
Одного не пойму. Почему почти все поголовно кинулись пихать в свои приложения ленточный интерфейс. Понятное дело Оффис с его огромным функционалом. Но ради трех кнопочек можно было обойтись и стандартным тулбаром, а не внедрять сторонний Ribbon компонент...
Ribbon использовать удобно для того, чтобы пальцами взаимодействовать с пользовательским интерфейсом. Плюс я планирую добавить новый фукнционал, так что польза от Риббон-Интерфейса ;)
Сайт является источником уникальной информации о семействе операционных систем Windows и других продуктах Microsoft. Перепечатка материалов возможна только с разрешения редакции.
Работает на WMS 2.34 (Страница создана за 0.03 секунд (Общее время SQL: 0.017 секунд - SQL запросов: 61 - Среднее время SQL: 0.00027 секунд))