Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C#

Interacting with and Displaying Online Maps

5.00/5 (3 votes)
25 Apr 2023GPL35 min read 12.3K  
Library for interacting with online map services and a WinUI 3 control for displaying maps
A library for interacting with online map services (Bing Maps, Google Maps, OpenStreetMap and OpenTopoMap are currently supported), plus WinUI 3 controls for displaying maps in WinUI 3 apps.

Introduction

I've written several Windows applications that involve displaying maps obtained from online services. Unfortunately, to my knowledge, there is no "official" Microsoft (or Microsoft community) control for displaying maps under WinUI 3. There are some available via GitHub, but I thought it would be an interesting project to develop my own.

The source code is available on GitHub.

Packages are available on Nuget.org:

Background

Like many others, I've used maps on many websites and in a number of desktop applications. But I wasn't familiar with the mechanics of how the various mapping services worked, which, completely aside from learning how to program them, was fascinating in its own right. A great place to start is with The Bing Maps Tile System which, in the course of explaining how their tile system works, will introduce you to why map services use tile-based systems and some of the challenges of using them in code libraries.

Using the Code

There is extensive documentation available for both libraries at the GitHub repository. The repository also contains a WinUI 3 demonstration program (which, admittedly, uses some of my other libraries, all of which are available from NuGet.org) and a set of unit tests, which also show how the J4JMapLibrary can be used. 

J4JMapLibrary

The J4JMapLibrary uses the concept of a "map region" (embodied in a MapRegion class), "map tiles" (embodied in a MapTile class) and a "projection" (embodied in a class derived from Projection, customized for dealing with a particular mapping service). The library currently has projection classes for Bing Maps, Google Maps, OpenStreetMap and OpenTopoMap. It shouldn't be too hard write your own projection class for another mapping service, either.

MapTiles are always part of a MapRegion, which defines the area of the map you want to display, its heading (i.e., how it may be rotated relative to true north) and its scale (i.e., how zoomed in it is). A Projection loads image data into a MapTile, or all the tiles contained in a MapRegion, which can then be used to update the UI. MapRegion contains various properties which make that updating easier (e.g., the horizontal and vertical offset of the display area relative to the area retrieved from the mapping service, which can differ).

While instantiating a Projection is straightforward, the library also contains a MapFactory which can be used to create Projections based on their name or type. MapFactory can also automatically authenticate a Projection (all of the mapping services require some degree of authentication to use them, and some also require you to set up accounts...which can incur fees if you use the service a lot). For MapFactory to do authentications, your credentials must be available through the IConfiguration system, and follow a particular layout. Details are contained in the GitHub documentation.

Some Projections support caching the retrieved image data (it is a violation of the Google Maps Static API to cache their image data). The library contains both an in-memory and a file system-based cache. Caching is not required but is recommended.

J4JMapWinLibrary

In and of itself, J4JMapLibrary doesn't actually display anything. And, because maps are inherently visual, the library will likely be of limited use in the command line environment.

J4JMapWinLibrary contains controls for displaying maps, and annotations, in a WinUI 3 application. It currently contains two controls, J4JMapControl (which displays maps) and MapPin (which can be used to display annotations "above" the map in a J4JMapControl).

Using J4JMapControl is simple: just add it to your app and assign certain properties to it.

XAML
<map:J4JMapControl x:Name="mapControl" 
                   Grid.Column="0" Grid.Row="0" Grid.ColumnSpan="3"
                   MapProjection="BingMaps"
                   MapScale="13"
                   Heading="45"
                           Center="37.5072N,122.2605W">

J4JMapControl has a reasonably long list of properties which you can use to tailor it to your needs. It offers the ability to display a compass rose (which shows the map's heading relative to true north) and a map scale slider control (which controls the map scale/zoom factor).

It also responds to click-and-drag actions. By default, those cause the center of the map to move to follow the mouse. But if you hold down the control key, the map rotates (i.e., its heading changes) in response to the mouse movements.

J4JMapControl will also respond to mouse wheel movements by changing the map scale/zoom factor.

The library also contains a MapPin control, which you can use to annotate locations on the map. Adding an annotation is simple in XAML:

XAML
<map:J4JMapControl x:Name="mapControl" 
                   Grid.Column="0" Grid.Row="0" Grid.ColumnSpan="3"
                   MapProjection="BingMaps"
                   MapScale="13"
                   Heading="45"
                   Center="37.5072N,122.2605W">

            <map:J4JMapControl.Annotations>
                
                <map:MapPin ArcRadius="15"
                            TailLength="30"                      
                            map:Location.Center="37.5072N,122.2605W" 
                            HorizontalAlignment="Center"
                            VerticalAlignment="Bottom" />

            </map:J4JMapControl.Annotations>

        </map:J4JMapControl>

Technically, any FrameworkElement can be used as an annotation, provided you assign it a Location property (i.e., the map:Location.Center reference in the code block above). Be aware, though, that the library currently doesn't "know" how to handle complex objects, so they likely won't be display properly, or at all.

Next Steps

The libraries are essentially complete at this point. There are a few minor bugs to resolve, and I also want to provide a mechanism for obtaining and storing the credentials required to access the supported map services.

Points of Interest

Developing these libraries taught me I knew almost nothing at all about online maps. I also learned that the geometry/mathematics of handling maps is insanely complicated compared to what I expected. There are multiple frames of reference you have to keep straight, and, since they all use the same underlying types, it's easy to get lost as to which one you're dealing with or how it must be converted to comply with the requirements of some other frame of reference.

History

  • 6th April, 2023: Initial public release (0.8)
  • 13th April, 2023: Bug fix, minor capability enhancements (0.8.3)
  • 25th April, 2023: Added DataTemplate based annotations (0.8.4)
  • 26th April, 2023: Added support for displaying routes (0.9)

License

This article, along with any associated source code and files, is licensed under The GNU General Public License (GPLv3)