How to Create Map Image Silently
Environment
| Product Version | Product | Author |
|---|---|---|
| 2021.2.615 | RadMap for WinForms | Desislava Yordanova |
Description
Learn how to export RadMap to an image silently from a Console application.

Solution
Please note that Bing Maps will be deprecated effective June 30, 2025. As an alternative, users can refer to the SDK example available in our GitHub repository, which demonstrates how to create a custom provider using the Azure Maps API. A valid Azure Maps subscription key is required to use this functionality.
The required assemblies that should be referred:
- System.Windows.Forms.dll
- System.Runtime.Serialization
- System.Drawing
- Telerik.WinControls
- Telerik.WinControls.RadMap
- Telerik.WinControls.UI
- Telerik.WinControls.UI
RadMap uses a MapTileDownloader which internally uses a WebClient calling its DownloadDataAsync method. It seems that in a console application the WebClient.DownloadDataCompleted event is not fired which is used in the MapTileDownloader. That is why the image that is created from the map is blank. That is why this example shows how to use the DownloadString method instead:
class Program
{
static string bingKey = "your Bing key";
static void Main(string[] args)
{
RadMap radMap1 = new RadMap();
radMap1.CreateControl();
CustomBingProvider bingProvider = new CustomBingProvider();
bingProvider.UseSession = false;
bingProvider.BingKey = bingKey;
bingProvider.TileDownloader = new CustomTileDownLoader(bingProvider);
radMap1.Providers.Add(bingProvider);
bingProvider.EnableCaching = false;
radMap1.MapElement.Providers.Add(bingProvider);
radMap1.ShowNavigationBar = true;
radMap1.ShowSearchBar = true;
radMap1.ShowScaleIndicator = true;
radMap1.ShowLegend = true;
radMap1.MapElement.LegendElement.TitleElement.Text = "NBA";
radMap1.MapElement.LegendElement.SubtitleElement.Text = "Conferences";
radMap1.MapElement.LegendElement.Orientation = Orientation.Horizontal;
radMap1.MapElement.LegendElement.ItemStackElement.Children.Add(new MapLegendItemElement("Western", Color.Red));
radMap1.MapElement.LegendElement.ItemStackElement.Children.Add(new MapLegendItemElement("Eastern", Color.Blue));
radMap1.LoadElementTree(new Size(1000, 1000));
radMap1.Providers[0].Initialize();
radMap1.MapElement.LegendElement.Initialize();
bingProvider.ViewportChanged(radMap1.MapElement, ViewportChangeAction.All);
radMap1.MapElement.InvalidateMeasure(true);
radMap1.MapElement.UpdateLayout();
var s = radMap1.MapElement.LegendElement.DesiredSize;
Bitmap b = radMap1.MapElement.GetAsBitmap(Brushes.Red, 0, new SizeF(1, 1));
b.Save(@"..\..\MapTest.png");
Process.Start(@"..\..\MapTest.png");
}
public class CustomBingProvider : BingRestMapProvider
{
private ImageryMetadata tileMetadataInfo;
private const string ImageryMetadataServiceUri = "https://dev.virtualearth.net/REST/v1/Imagery/Metadata/{set}?output=json&key={key}&c={culture}&dir={directory}";
protected override void InitializeImageryService()
{
this.tileMetadataInfo = null;
try
{
string uriString = ImageryMetadataServiceUri;
uriString = uriString.Replace("{set}", this.ImagerySet.ToString());
uriString = uriString.Replace("{key}", string.IsNullOrEmpty(this.SessionId) ? this.BingKey : this.SessionId);
uriString = uriString.Replace("{culture}", this.Culture.ToString());
uriString = uriString.Replace("{directory}", "0");
WebClient client = new WebClient();
//client.DownloadStringCompleted += this.InitializeImageryMetadataCompleted;
//client.DownloadStringAsync(new Uri(uriString, UriKind.Absolute));
string result = client.DownloadString(new Uri(uriString, UriKind.Absolute));
InitializeImageryMetadataCompleted(client, result);
}
catch (Exception ex)
{
throw new Exception(string.Format("Imagery Service Exception: {0}", ex.Message));
}
}
protected virtual void InitializeImageryMetadataCompleted(object sender, string result)
{
this.tileMetadataInfo = null;
WebClient client = sender as WebClient;
// client.DownloadStringCompleted -= InitializeImageryMetadataCompleted;
try
{
#if NET2
using (StringReader reader = new StringReader(result))
{
JsonSerializer serializer = new JsonSerializer();
ImageryMetadataResponse response = serializer.Deserialize<ImageryMetadataResponse>(new JsonTextReader(reader));
if (response != null && response.ResourceSets.Length > 0 && response.ResourceSets[0].Resources.Length > 0)
{
this.tileMetadataInfo = response.ResourceSets[0].Resources[0];
if (this.tileMetadataInfo.ImageUrl.StartsWith("http://") && this.ImagerySet == ImagerySet.OrdnanceSurvey)
{
this.tileMetadataInfo.ImageUrl = this.tileMetadataInfo.ImageUrl.Replace("http://", "https://");
}
this.tileSize = new Size(int.Parse(this.tileMetadataInfo.ImageWidth), int.Parse(this.tileMetadataInfo.ImageHeight));
this.MinZoomLevel = tileMetadataInfo.ZoomMin;
this.MaxZoomLevel = tileMetadataInfo.ZoomMax;
}
}
#else
using (MemoryStream stream = new MemoryStream(Encoding.UTF8.GetBytes(result)))
{
DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(ImageryMetadataResponse));
ImageryMetadataResponse response = serializer.ReadObject(stream) as ImageryMetadataResponse;
if (response != null && response.ResourceSets.Length > 0 && response.ResourceSets[0].Resources.Length > 0)
{
this.tileMetadataInfo = response.ResourceSets[0].Resources[0];
FieldInfo fi = typeof(BingRestMapProvider).GetField("tileSize", BindingFlags.Instance | BindingFlags.NonPublic);
fi.SetValue(this, new System.Drawing.Size(int.Parse(this.tileMetadataInfo.ImageWidth), int.Parse(this.tileMetadataInfo.ImageHeight)));
// this.tileSize = new System.Drawing.Size(int.Parse(this.tileMetadataInfo.ImageWidth), int.Parse(this.tileMetadataInfo.ImageHeight));
this.MinZoomLevel = tileMetadataInfo.ZoomMin;
this.MaxZoomLevel = tileMetadataInfo.ZoomMax;
}
}
#endif
}
#if NET2
catch (JsonSerializationException) { }
#else
catch (SerializationException) { }
#endif
FieldInfo ti = typeof(BingRestMapProvider).GetField("tileMetadataInfo", BindingFlags.Instance | BindingFlags.NonPublic);
ti.SetValue(this, this.tileMetadataInfo);
this.Initialized = true;
this.OnInitializationComplete(EventArgs.Empty);
}
}
public class CustomTileDownLoader : MapTileDownloader
{
private IMapTileProvider provider;
public CustomTileDownLoader(IMapTileProvider provider)
{
this.provider = provider;
}
public override void BeginDownloadTile(Uri uri, TileInfo tileInfo)
{
lock (this.webClientsPoolLockObject)
{
if (!this.webClientsPool.ContainsKey(tileInfo.Quadkey))
{
WebClient client = new WebClient();
foreach (string key in this.WebHeaders.AllKeys)
{
client.Headers.Add(key, this.WebHeaders[key]);
}
this.webClientsPool.Add(tileInfo.Quadkey, client);
this.webRequestCache.Add(tileInfo.Quadkey, uri);
//client.DownloadDataCompleted += TileDownloadDataCompleted;
//client.DownloadDataAsync(uri, tileInfo);
tileInfo.Content = client.DownloadData(uri);
if (provider.EnableCaching && provider.CacheProvider != null)
{
provider.CacheProvider.Save(GetCacheKey(tileInfo.TileX, tileInfo.TileY, tileInfo.ZoomLevel), DateTime.MaxValue, tileInfo.Content);
}
}
}
}
private string GetCacheKey(int tileX, int tileY, int zoomLevel)
{
return "Tile_" + tileX + "_" + tileY + "_" + zoomLevel + ".png";
}
}
}
Make sure that the following using/imports are added:
using System;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Net;
using System.Reflection;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Json;
using System.Text;
using System.Windows.Forms;
using Telerik.WinControls.UI;
using Telerik.WinControls.UI.Map.Bing;