I have a situation where we have an offline tile cache used for a basemap for imagery. We also want to be able to use the online streets basemap if connected. This seems straightforward, however, does not work. If I initially load a tiles layer as basemap I am unable to switch the basemap to a basemap that uses service layers and vice-versa.
So if I initially load tiles:
<SPAN class="keyword token">var</SPAN> tileCache <SPAN class="operator token">=</SPAN> <SPAN class="keyword token">new</SPAN> <SPAN class="token class-name">TileCache</SPAN><SPAN class="punctuation token">(</SPAN><SPAN class="string token">@"D:\Mobile\Imagery\Layers"</SPAN><SPAN class="punctuation token">)</SPAN><SPAN class="punctuation token">;</SPAN>
ArcGISTiledLayer imageLayer <SPAN class="operator token">=</SPAN> <SPAN class="keyword token">new</SPAN> <SPAN class="token class-name">ArcGISTiledLayer</SPAN><SPAN class="punctuation token">(</SPAN>tileCache<SPAN class="punctuation token">)</SPAN><SPAN class="punctuation token">;</SPAN>
map <SPAN class="operator token">=</SPAN> <SPAN class="keyword token">new</SPAN> <SPAN class="token class-name">Esri<SPAN class="punctuation token">.</SPAN>ArcGISRuntime<SPAN class="punctuation token">.</SPAN>Mapping<SPAN class="punctuation token">.</SPAN>Map</SPAN><SPAN class="punctuation token">(</SPAN><SPAN class="keyword token">new</SPAN> <SPAN class="token class-name">Basemap</SPAN><SPAN class="punctuation token">(</SPAN>imageLayer<SPAN class="punctuation token">)</SPAN><SPAN class="punctuation token">)</SPAN> <SPAN class="punctuation token">{</SPAN> InitialViewpoint <SPAN class="operator token">=</SPAN> <SPAN class="keyword token">new</SPAN> <SPAN class="token class-name">Viewpoint</SPAN><SPAN class="punctuation token">(</SPAN>extent<SPAN class="punctuation token">)</SPAN> <SPAN class="punctuation token">}</SPAN><SPAN class="punctuation token">;</SPAN><SPAN class="line-numbers-rows"><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN></SPAN>The offline cache loads correctly. However, when I try to switch the reference to a service based basemap
RuntimeControls<SPAN class="punctuation token">.</SPAN>MapView<SPAN class="punctuation token">.</SPAN>Map<SPAN class="punctuation token">.</SPAN>Basemap <SPAN class="operator token">=</SPAN> Basemap<SPAN class="punctuation token">.</SPAN><SPAN class="token function">CreateStreets</SPAN><SPAN class="punctuation token">(</SPAN><SPAN class="punctuation token">)</SPAN><SPAN class="punctuation token">;</SPAN><SPAN class="line-numbers-rows"><SPAN></SPAN></SPAN>
The base map simply disappears (in the above RuntimeControls is used to share the MapView across the application.
If instead of the first code block I start with:
map <SPAN class="operator token">=</SPAN> <SPAN class="keyword token">new</SPAN> <SPAN class="token class-name">Esri<SPAN class="punctuation token">.</SPAN>ArcGISRuntime<SPAN class="punctuation token">.</SPAN>Mapping<SPAN class="punctuation token">.</SPAN>Map</SPAN><SPAN class="punctuation token">(</SPAN>Basemap<SPAN class="punctuation token">.</SPAN><SPAN class="token function">CreateImageryWithLabelsVector</SPAN><SPAN class="punctuation token">(</SPAN><SPAN class="punctuation token">)</SPAN><SPAN class="punctuation token">)</SPAN> <SPAN class="punctuation token">{</SPAN> InitialViewpoint <SPAN class="operator token">=</SPAN> <SPAN class="keyword token">new</SPAN> <SPAN class="token class-name">Viewpoint</SPAN><SPAN class="punctuation token">(</SPAN>extent<SPAN class="punctuation token">)</SPAN> <SPAN class="punctuation token">}</SPAN><SPAN class="punctuation token">;</SPAN><SPAN class="line-numbers-rows"><SPAN></SPAN></SPAN>Switching basemaps in the second block works fine. The opposite behavior is also observed. If I initially start with a Streets layer for basemap, I am unable to switch the basemap to the TileCache. However, when I switch back to the TileCache after the failed attempt to change to streets the basemap is displayed.
The only thing that works is to create a new Map instance. The problem with this is the OperationalLayers are lost. I tried a workaround to see if I can recreate the map. Along these lines
RuntimeControls<SPAN class="punctuation token">.</SPAN>MapView<SPAN class="punctuation token">.</SPAN>Map<SPAN class="punctuation token">.</SPAN>Basemap <SPAN class="operator token">=</SPAN> Basemap<SPAN class="punctuation token">.</SPAN><SPAN class="token function">CreateStreets</SPAN><SPAN class="punctuation token">(</SPAN><SPAN class="punctuation token">)</SPAN><SPAN class="punctuation token">;</SPAN>
LayerCollection operationalLayers <SPAN class="operator token">=</SPAN> RuntimeControls<SPAN class="punctuation token">.</SPAN>MapView<SPAN class="punctuation token">.</SPAN>Map<SPAN class="punctuation token">.</SPAN>OperationalLayers<SPAN class="punctuation token">;</SPAN>
Envelope extent <SPAN class="operator token">=</SPAN> RuntimeControls<SPAN class="punctuation token">.</SPAN>MapView<SPAN class="punctuation token">.</SPAN>VisibleArea<SPAN class="punctuation token">.</SPAN>Extent<SPAN class="punctuation token">;</SPAN>
RuntimeControls<SPAN class="punctuation token">.</SPAN>MapView<SPAN class="punctuation token">.</SPAN>Map <SPAN class="operator token">=</SPAN> <SPAN class="keyword token">null</SPAN><SPAN class="punctuation token">;</SPAN>
Map map <SPAN class="operator token">=</SPAN> <SPAN class="keyword token">new</SPAN> <SPAN class="token class-name">Map</SPAN><SPAN class="punctuation token">(</SPAN>Basemap<SPAN class="punctuation token">.</SPAN><SPAN class="token function">CreateStreets</SPAN><SPAN class="punctuation token">(</SPAN><SPAN class="punctuation token">)</SPAN><SPAN class="punctuation token">)</SPAN> <SPAN class="punctuation token">{</SPAN> InitialViewpoint <SPAN class="operator token">=</SPAN> <SPAN class="keyword token">new</SPAN> <SPAN class="token class-name">Viewpoint</SPAN><SPAN class="punctuation token">(</SPAN>extent<SPAN class="punctuation token">)</SPAN> <SPAN class="punctuation token">}</SPAN><SPAN class="punctuation token">;</SPAN>
<SPAN class="keyword token">foreach</SPAN> <SPAN class="punctuation token">(</SPAN><SPAN class="keyword token">var</SPAN> layer <SPAN class="keyword token">in</SPAN> operationalLayers<SPAN class="punctuation token">.</SPAN>OfType<SPAN class="operator token"><</SPAN>FeatureLayer<SPAN class="operator token">></SPAN><SPAN class="punctuation token">(</SPAN><SPAN class="punctuation token">)</SPAN><SPAN class="punctuation token">)</SPAN>
<SPAN class="punctuation token">{</SPAN>
FeatureLayer featureLayer <SPAN class="operator token">=</SPAN> <SPAN class="keyword token">new</SPAN> <SPAN class="token class-name">FeatureLayer</SPAN><SPAN class="punctuation token">(</SPAN>layer<SPAN class="punctuation token">.</SPAN>FeatureTable<SPAN class="punctuation token">)</SPAN><SPAN class="punctuation token">;</SPAN>
map<SPAN class="punctuation token">.</SPAN>OperationalLayers<SPAN class="punctuation token">.</SPAN><SPAN class="token function">Add</SPAN><SPAN class="punctuation token">(</SPAN>featureLayer<SPAN class="punctuation token">)</SPAN><SPAN class="punctuation token">;</SPAN>
<SPAN class="punctuation token">}</SPAN><SPAN class="line-numbers-rows"><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN></SPAN>This, though, throws an exception:
Esri.ArcGISRuntime.ArcGISRuntimeException was unhandled
ErrorCode=24
HResult=-2146233088
Message=Object already owned.: Already owned.
Source=Esri.ArcGISRuntime
I put the line setting the map to null in there hoping it would release the layer ownership, I even tried to force a garbage collection to see if that would release it, but no luck.
Any thoughts? This is a pretty critical aspect to our application users need to be able to see a streets map when they are connected
Thanks
-Joe