Создаем контекстно-зависимое WPF-приложение

Автор: Topol Воскресенье, Май 6th, 2012 Нет комментариев

Рубрика: Операционные системы

Начинаем цикл публикаций, призванных помочь начинающим программистам в создании контекстно-зависимых приложений для 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-приложении.

Вот, собственно, и все. В следующий раз мы поговорим о том, как проверить статус платформы, о том, что делать в случае, если доступ запрещен, и что делать с провайдером, используемым по умолчанию.

Источник: thevista.ru

Оставить комментарий

Чтобы оставлять комментарии Вы должны быть авторизованы.

Похожие посты