Skip to main content Skip to footer

How to Connect WinForms Maps to OpenStreetMap Tiles

ComponentOne includes the C1Map control that allows you to display geographical data on a map in your WinForms application. You can display geographical information from various built-in and custom sources. By default, C1Map provides three built-in sources, Aerial, Road, and Hybrid views which access Microsoft Bing Maps. In this blog, we will see how we can create a custom tile source for C1Map using tile images from OpenStreetMap in two easy steps, and we will add an optional third step to support offline users.

  1. Create a Custom Tile Source
  2. Use the Custom Tile Source in the Map Control
  3. (Optional) Support Offline Maps

Ready to Get Started? Download ComponentOne Today!

Create a Custom Tile Source

The first step to creating a custom tile source is implementing the ITileSource interface provided by the C1Map control.

public interface ITileSource
    {
        int TileWidth { get; }
        int TileHeight { get; }

        void GetTile(int level, int x, int y, out string uri, out object image);
    }

The ITileSource interface provides the GetTile method to implement. The GetTile method receives the zoom level, tile’s x position, and tile’s y position, based on which we can then assign either the Uri or an image of the tile.

Since we are using the OpenStreetMap as our online map source, we will use the following Uri to get the tile for the specified zoom level and x and y positions.

http://tile.openstreetmap.org/{zoom}/{x}/{y}.png

Now, we need to use the parameters in the GetTile method, create the corresponding OpenStreetMap Uri and assign it to the Uri parameter. Since we are not providing any image, we can set the image parameter to null. After the full implementation, our custom tile source will look something like this:

public class OpenStreetTileSource : ITileSource
    {
        private const string UrlTemplate = "http://tile.openstreetmap.org/{0}/{1}/{2}.png";

        public void GetTile(int zoomLevel, int tilePositionX, int tilePositionY, out string url, out object image)
        {
            image = null;
            url = string.Format(UrlTemplate, zoomLevel, tilePositionX, tilePositionY);
        }

        public int TileWidth { get { return 256; } }
        public int TileHeight { get { return 256; } }

    }

Use the Custom Tile Source in the Map Control

Having created our custom tile source, the next step is to assign it to the C1Map control. This can be done by using the C1Map.TileLayer.TileSource property as shown below.       

     c1Map1.TileLayer.TileSource = _customMapSource;

Once we assign the custom tile source, the map will look like the following:

WinForms Maps

I’ve provided a complete sample you can download at the end of the article.

Optional - Support Offline Maps

You might have noticed that in the custom tile source, we utilized an online map source to get the tile images. However, in some scenarios, displaying the map without an internet connection may be necessary. To do that, we can create an offline custom tile source by modifying our implementation of ITileSource. Instead of assigning the Uri in the GetTile method, we need to load the local tile image and assign the Image in the GetTile method. After the full implementation, our offline tile source will look something like this:

public class OfflineTilesSource : ITileSource
    {
        private readonly string tilesLocation;
        public OfflineTilesSource(string tilesLocation)
        {
            if (Directory.Exists(tilesLocation))
            {
                this.tilesLocation = Path.Combine(tilesLocation);
            }
            else
                throw new DirectoryNotFoundException();
        }
        public int TileWidth { get { return 256; } }
        public int TileHeight { get { return 256; } }

        public void GetTile(int level, int x, int y, out string uri, out object image)
        {
            uri = string.Empty;
            image = null;

            var imgPath = Path.Combine(tilesLocation, level.ToString(), x.ToString(), (y.ToString() + ".png"));
            if (File.Exists(imgPath))
            {
                using (Bitmap bmp = new Bitmap(imgPath))
                {
                    image = new Bitmap(bmp);
                }
            }
        }

    }

Now, to load and assign the correct tile image, we must have the tile images saved locally in a manner that allows for easy retrieval based on the tile's position and zoom level. For this blog’s sample project, we have stored the tile images in folders labeled with numerical values. The folders are structured such that the first level corresponds to the zoom level, the second level corresponds to the x position, and the third level corresponds to the y position.

WinForms Maps

Within the y position folders, we can find the tile images. This arrangement enables us to access the required images easily by utilizing the values provided by the GetTile method.

You can explore the sample application and experience how simple creating a custom tile source with offline support for the C1Map control is.

Ready to Get Started? Download ComponentOne Today!

comments powered by Disqus