This question is locked. New answers and comments are not allowed.
It seems that the BingMapProvider has a few problems that cause memory leaks.
Please find some sample code below.
My sample application basically contains a grid to which I add a 'MapWrapper' control. Every 3 seconds, the MapWrapper is removed, and a new MapWrapper is added.
The MapWrapper is a simple control that contains a RadMap.
There are two buttons shown on top of the MapWrapper.
The first button allows to turn on/off the 3-second timer.
The second button allows to switch between a BingMapProvider and an OpenStreetMapProvider. Every time a new MapWrapper is instantiated, a provider of the chosen type is set as provider for the RadMap.
Letting the application run for a while using OSM, there are no problems.
However, when using the BingMapProvider, two problems occur:
1) Not a single instance of BingMapProvider is ever released, and this creates a huge memory leak, especially in our live application where the Map control has several layers of data.
(OpenStreetMapProvider objects on the other hand are always removed -- even without any custom implementation of Dispose)
2) Frequently and irregularly, WinDbg shows the following two lines while creating the BingMapProvider:
(604.c74): CLR exception - code e0434352 (first chance)
(604.1868): CLR exception - code e0434352 (first chance)
Every time that this exception occurs, the map simply fails to show anything.
Both problems are huge game breakers and prevent us from using Bing in our application.
One thing I haven't tried is setting the Bing provider in XAML instead of in code behind -- who knows it might solve the issue. One reason is that I'm just not sure how to do that (with OSM it's pretty straightforward, but Bing requires a key and stuff). The second reason is that in our live application we want our client to be able to switch between providers on the fly, so we HAVE to be able to it in code-behind anyway.
I've already created a support ticket for this issue, but I'm posting it here to in case anyone has any ideas.
Please find some sample code below.
My sample application basically contains a grid to which I add a 'MapWrapper' control. Every 3 seconds, the MapWrapper is removed, and a new MapWrapper is added.
The MapWrapper is a simple control that contains a RadMap.
There are two buttons shown on top of the MapWrapper.
The first button allows to turn on/off the 3-second timer.
The second button allows to switch between a BingMapProvider and an OpenStreetMapProvider. Every time a new MapWrapper is instantiated, a provider of the chosen type is set as provider for the RadMap.
Letting the application run for a while using OSM, there are no problems.
However, when using the BingMapProvider, two problems occur:
1) Not a single instance of BingMapProvider is ever released, and this creates a huge memory leak, especially in our live application where the Map control has several layers of data.
(OpenStreetMapProvider objects on the other hand are always removed -- even without any custom implementation of Dispose)
2) Frequently and irregularly, WinDbg shows the following two lines while creating the BingMapProvider:
(604.c74): CLR exception - code e0434352 (first chance)
(604.1868): CLR exception - code e0434352 (first chance)
Every time that this exception occurs, the map simply fails to show anything.
Both problems are huge game breakers and prevent us from using Bing in our application.
One thing I haven't tried is setting the Bing provider in XAML instead of in code behind -- who knows it might solve the issue. One reason is that I'm just not sure how to do that (with OSM it's pretty straightforward, but Bing requires a key and stuff). The second reason is that in our live application we want our client to be able to switch between providers on the fly, so we HAVE to be able to it in code-behind anyway.
I've already created a support ticket for this issue, but I'm posting it here to in case anyone has any ideas.
<UserControl x:Class="TestRadMapBlurriness.MainPage" mc:Ignorable="d" d:DesignHeight="300" d:DesignWidth="400"> <Grid x:Name="LayoutRoot" Background="White"> <Grid Name="GridMap" /> <StackPanel HorizontalAlignment="Left" VerticalAlignment="Top" Margin="30"> <Button Name="BtnTimer" Content="Start" Click="BtnTimer_Click" MinWidth="120" /> <Button Name="BtnProvider" Content="BING" Click="BtnProvider_Click" MinWidth="120"/> </StackPanel> </Grid></UserControl>public partial class MainPage : UserControl { public MainPage() { InitializeComponent(); // Prepare the timer that will recreate a new MapWrapper every x seconds _refreshDataTimer = new DispatcherTimer { Interval = new TimeSpan(0, 0, 3) }; _refreshDataTimer.Tick += refreshDataTimer_Tick; // Label the buttons BtnTimer.Content = "Start"; BtnProvider.Content = "BING"; } private DispatcherTimer _refreshDataTimer; void refreshDataTimer_Tick(object sender, EventArgs e) { Refresh(); } private int _refreshCounter = 0; private void Refresh() { // Remove any existing maps while (true) { MapWrapper mapWrapper = GridMap.Children.OfType<MapWrapper>().FirstOrDefault(); if (mapWrapper == null) break; Debug.WriteLine((_refreshCounter).ToString() + ": {0:x16} Removing MapWrapper", mapWrapper.GetHashCode()); mapWrapper.Dispose(); GridMap.Children.Remove(mapWrapper); } // Add a new map MapWrapper newMapWrapper = new MapWrapper(_providerName); GridMap.Children.Add(newMapWrapper); Debug.WriteLine((_refreshCounter++).ToString() + ": {0:x16} Added new MapWrapper", newMapWrapper.GetHashCode()); } /// <summary> /// Start/stop the timer /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void BtnTimer_Click(object sender, RoutedEventArgs e) { if (BtnTimer.Content.ToString() == "Stop") { _refreshDataTimer.Stop(); BtnTimer.Content = "Start"; } else { _refreshDataTimer.Start(); BtnTimer.Content = "Stop"; } } private string _providerName = ""; /// <summary> /// Change the provider. The next new MapWrapper will be initialized with the new provider. /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void BtnProvider_Click(object sender, RoutedEventArgs e) { if (BtnProvider.Content.ToString() == "BING") { _providerName = "OpenStreetMapProvider"; BtnProvider.Content = "OSM"; } else { _providerName = ""; BtnProvider.Content = "BING"; } } }<UserControl x:Class="TestRadMapBlurriness.MapWrapper" xmlns:telerik="http://schemas.telerik.com/2008/xaml/presentation" mc:Ignorable="d" d:DesignHeight="300" d:DesignWidth="400"> <Grid x:Name="LayoutRoot" Background="White"> <telerik:RadMap x:Name="RadMap1" Center="38.8763793426777, -77.0368488348389" ZoomLevel="14" MiniMapExpanderVisibility="Collapsed" > <!--<telerik:RadMap.Providers>--> <!--<telerik:OpenStreetMapProvider />--> <!--<telerik:BingMapTrafficProvider />--> <!--</telerik:RadMap.Providers>--> </telerik:RadMap> </Grid></UserControl>public partial class MapWrapper : UserControl, IDisposable { private string _providerName = ""; public MapWrapper(string providerName) { InitializeComponent(); _providerName = providerName; SetProvider(); } private const double BaseAerialLayerOpacity = 1.0; private const double RoadLayerOpacity = 0.5; private void SetProvider() { MapProviderBase provider; if (_providerName == "OpenStreetMapProvider") { provider = new OpenStreetMapProvider(); } else { var bingMapId = ((Microsoft.Maps.MapControl.ApplicationIdCredentialsProvider)App.Current.Resources["AppId"]).ApplicationId; BingMapProvider baseAerialProvider = new BingMapProvider(MapMode.Aerial, true, bingMapId); provider = baseAerialProvider; } this.RadMap1.Provider = provider; } #region Dispose private bool _disposed = false; public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } protected virtual void Dispose(bool disposing) { try { Debug.WriteLine("Dispose(" + disposing.ToString() + ") {0:x16}", this.GetHashCode()); if (!_disposed) { if (disposing) { // Free managed objects //this.RadMap1.Providers.Clear(); //this.RadMap1.Provider = null; RadMap1.Dispose(); Debug.WriteLine("Dispose manually {0:x16}", this.GetHashCode()); } else { } //this.RadMap1.Providers.RemoveAll(); //Debug.WriteLine("this.RadMap1.Providers.RemoveAll();"); _disposed = true; } } catch (Exception ex) { Debug.WriteLine("Dispose(" + disposing.ToString() + ") failed: " + ex.Message); } } ~MapWrapper() { Dispose(false); } #endregion