Блог Сергея Байдачного

Мой блог о технологиях

Использование карт (часть 2)

leave a comment »

Расширение возможностей по работе с картами

Очень много задач не только требуют отобразить карту и какие-то элементы на ней, но и реализовать поиск координат места по названию и наоборот, отобразить путь, посчитать расстояние до цели и др. Карты от Nokia позволяют реализовывать и все эти задачи. Для этого обратимся к пространству имен Microsoft.Phone.Maps.Services, где содержатся все утилитные классы.

Как-то мне выдали топливную карточку и я очень хотел написать приложение, которое выдает на карте ближайшие заправки, которые принимают эту карточку. Проблема в том, что для каждой заправки был ее адрес, но не было GPS позиции, поэтому пришлось ограничится списком заправок по областям и городам без привязки карты. Давайте посмотрим, как можно найти GPS позицию по адресу, используя новый набор классов.

Чтобы найти позицию по адресу, необходимо использовать класс GeocodeQuery. Этот класс содержит два свойства, которые позволяют установить начальные параметры для поиска, это SearchTerm и GeoCoordinate. Первое свойство SearchTerm позволяет задать параметры поиска. Тут не обязательно должен быть точный адрес, так как класс GeocodeQuery позволяет получить коллекцию результатов поиска. Поскольку результатов может быть несколько, то для правильной сортировки и оптимизации поиска задается свойство GeoCoodinate. Обычно это свойство задает текущую позицию устройства и позволяет не выдавать заведомо бесполезные результаты (например, адреса в США, когда Вы находитесь в Украине). При сложных сценариях GeoCoordinate можно устанавливать в любую позицию.

Создав объект типа GeocodeQuery и задав основные свойства, можно переходить к поиску. Для этого используется метод QueryAsync, который после своего завершения работы инициирует событие QueryCompleted. Поэтому, следует повесить обработчик события QueryCompleted и можно вызывать метод. Внутри обработчика события QueryCompleted следует проверить количество результатов и возможность возникновения ошибки. Вот небольшой пример кода, который выполняет поиск адреса:

 

 private async void OneShotLocation_Click()
 {
     GeocodeQuery MyGeocodeQuery = new GeocodeQuery();
     MyGeocodeQuery.SearchTerm = "Dnepropetrovsk, Marksa 101";
     MyGeocodeQuery.GeoCoordinate = new GeoCoordinate(50.4556, 30.5143);

     MyGeocodeQuery.QueryCompleted += MyGeocodeQuery_QueryCompleted;
     MyGeocodeQuery.QueryAsync();
 }

 void MyGeocodeQuery_QueryCompleted(object sender, 
          QueryCompletedEventArgs<IList<MapLocation>> e)
{
    if ((e.Error == null)&&(e.Result.Count>0))
    {
        Ellipse myCircle = new Ellipse();
        myCircle.Fill = new SolidColorBrush(Colors.Blue);
        myCircle.Height = 20;
        myCircle.Width = 20;
        myCircle.Opacity = 50;

        MapOverlay myLocationOverlay = new MapOverlay();
        myLocationOverlay.Content = myCircle;
        myLocationOverlay.PositionOrigin = new Point(0.5, 0.5);
        myLocationOverlay.GeoCoordinate =
            e.Result.First().GeoCoordinate;

        MapLayer myLocationLayer = new MapLayer();
        myLocationLayer.Add(myLocationOverlay);

        myMap.Layers.Add(myLocationLayer);
        myMap.SetView(e.Result.First().GeoCoordinate, 14);
    }
}

 

Обратите внимание на то, что QueryAsync не поддерживает возможность использовать подход await/async, а требует создания обработчика.

Используя коллекцию результатов можно предоставить пользователю выбор, а если более детально посмотреть на содержимое e.Result, то можно получить не только координаты, но и район города. Тут используются объекты классов MapLocation и MapAddress.

Если у Вас обратная задача и по GPS координатам необходимо найти адрес, то это также можно легко сделать с помощью класса ReverseGeocodeQuery:

 

ReverseGeocodeQuery MyGeocodeQuery = new ReverseGeocodeQuery();
MyGeocodeQuery.GeoCoordinate = new GeoCoordinate(50.4556, 30.5143);

MyGeocodeQuery.QueryCompleted += MyGeocodeQuery_QueryCompleted;
MyGeocodeQuery.QueryAsync();

 

Тут только один параметр для поиска – координаты места, адрес которого необходимо найти.

Остается еще одна задача, которую можно выполнить с помощью карт Nokia, это прокладка пути. При этом путь можно проложить как для пешехода, так и для автомобиля, получив все данные, которые дают современные GPS системы. Тут используется класс RouteQuery, который содержит три основных свойства:

· RouteOptimization – позволяет задать параметр, определяющий оптимальный для пользователя путь: экономный по расстоянию или по времени;

· TravelMode – позволяет указать, как будет передвигаться пользователь: пешком или на автомобиле;

· Waypoints – содержит коллекцию объектов типа GeoCoordinate, перечисляющую те места, где планирует побывать пользователь (в самом простом случае, это начало и конец пути).

Вот пример кода, который задает основные параметры для объекта класса RouteQuery:

 

private async void OneShotLocation_Click()
{
    RouteQuery query = new RouteQuery();
    query.RouteOptimization = RouteOptimization.MinimizeDistance;
    query.TravelMode = TravelMode.Driving;
    query.Waypoints = new List<GeoCoordinate>()
        {
            new GeoCoordinate(50.46,30.5303),
            new GeoCoordinate(50.4556,30.5143)
        };

    query.QueryCompleted += query_QueryCompleted;
    query.QueryAsync();
}

 

Обработчик события QueryCompleted содержит объект типа Route, который можно тут же добавить на карту:

 

void query_QueryCompleted(object sender, QueryCompletedEventArgs<Route> e)
{
    MapRoute MyMapRoute = new MapRoute(e.Result);
    myMap.AddRoute(MyMapRoute);
    myMap.SetView(e.Result.BoundingBox);
}

 

Исследуя объект типа Route, можно получить всю необходимую информацию. Например, коллекция Geometry содержит набор объектов типа GeoCoordinate, из которых строится путь, а свойство Legs позволяет получить время пути, расстояние и список мест, где необходимо выполнить изменение пути (инструкций). Все это можно использовать для построения системы любой сложности.

Расширение возможностей с помощью Windows Phone toolkit

Если Вы используете в своем приложении Windows Phone Toolkit, который можно найти по адресу http://phone.codeplex.com/, то можете немного расширить возможности существующего API для карт дополнительными методами и классами.

Как Вы заметили, все асинхронные методы стандартного API требуют создания обработчика события. Windows Phone Toolkit расширяет эти существующие методы аналогами, работающими через async/await. Так, метод GetRouteAsync расширяет класс RouteQuery, а методом GetMapLocationsAsync расширяются классы GeocodeQuery и ReverseGeocodeQuery. Так, предыдущий пример будет выглядеть следующим образом:

 

private async void OneShotLocation_Click()
{
    RouteQuery query = new RouteQuery();
    query.RouteOptimization = RouteOptimization.MinimizeDistance;
    query.TravelMode = TravelMode.Driving;
    query.Waypoints = new List<GeoCoordinate>()
        {
            new GeoCoordinate(50.46,30.5303),
            new GeoCoordinate(50.4556,30.5143)
        };

    query.QueryCompleted += query_QueryCompleted;
    Route r=await query.GetRouteAsync();

    MapRoute MyMapRoute = new MapRoute(r);
    myMap.AddRoute(MyMapRoute);
    myMap.SetView(r.BoundingBox);
}

 

Кроме асинхронных методов, Windows Phone Toolkit расширяет возможности класса Map. Во-первых, тут появляется класс Pushpin, который был в Bing Maps SDK и представляет собой готовую метку для карт. Данные метки можно установить с помощью расширения Children, задающего коллекцию элементов на карте. Во-вторых, тут появился MapItemsControl, который также добавляется в коллекцию Children, но при этом сам является источником для коллекции данных, позволяя реализовать механизм связывания карты и данных.

Ниже пример инициализации коллекции Children и добавления в нее элемента PushPin:

 

ObservableCollection<DependencyObject> children = 
MapExtensions.GetChildren(myMap);

children.Add(new Pushpin() 
{ 
GeoCoordinate = new GeoCoordinate(50.46, 30.5303) 
});

 

А вот этот пример показывает, как можно определить связывание карты и данных в XAML:

 

<maps:Map x:Name="Map" Grid.Row="1" Hold="OnMapHold">
    <maptk:MapExtensions.Children>
        <maptk:Pushpin x:Name="RouteDirectionsPushPin"           
                       Visibility="Collapsed"/>
        <maptk:MapItemsControl Name="StoresMapItemsControl">
            <maptk:MapItemsControl.ItemTemplate>
                <DataTemplate>
                    <maptk:Pushpin GeoCoordinate="{Binding GeoCoordinate}" 
                                   Visibility="{Binding Visibility}" 
                                   Content="{Binding Address}"/>
                </DataTemplate>
            </maptk:MapItemsControl.ItemTemplate>
        </maptk:MapItemsControl>
        <maptk:UserLocationMarker x:Name="UserLocationMarker" 
                                  Visibility="Collapsed"/>
    </maptk:MapExtensions.Children>
</maps:Map>

 

Тут также используется класс UserLocationMarker, который аналогичен Pushpin, но аналогичен большинству элементов, показывающих текущую позицию.

Как видите, если у Вас используется связывание с данными, то Toolkit очень полезен. Более того, его можно использовать для миграции Ваших приложений с WP 7 на WP 8.

Реклама

Written by Sergiy Baydachnyy

16.12.2012 в 11:18

Опубликовано в Windows Phone

Tagged with

Добавить комментарий

Заполните поля или щелкните по значку, чтобы оставить свой комментарий:

Логотип WordPress.com

Для комментария используется ваша учётная запись WordPress.com. Выход / Изменить )

Фотография Twitter

Для комментария используется ваша учётная запись Twitter. Выход / Изменить )

Фотография Facebook

Для комментария используется ваша учётная запись Facebook. Выход / Изменить )

Google+ photo

Для комментария используется ваша учётная запись Google+. Выход / Изменить )

Connecting to %s

%d такие блоггеры, как: