C1MapVirtualLayer displays elements over the map supporting virtualization and asynchronous data loading. It can be used to display an unlimited number of elements, as long as not many of them are visible at the same time. Its object model is quite different from C1MapItemsLayer; C1MapVirtualLayer requires a division of the map space in regions, and the items' source must implement the IMapVirtualSource interface.
The division of map space is defined using the C1MapVirtualLayer.Slices collection of MapSlice. Each map slice defines a minimum zoom level for its division, and the maximum zoom level for a slice is the minimum zoom layer of the next slice (or, if it is the last slice, its maximum zoom level is the maximum zoom of the map). In turn, each slice is divided in a grid of latitude/longitude divisions.
Take the following layer as an example:
C# |
Copy Code
|
---|---|
var layer = new C1MapVirtualLayer { Slices = { new MapSlice(2, 2, 5), new MapSlice(4, 4, 10) } }; |
There are two slices: one goes from zoom 5 to 10, and the other one from zoom 10 to the maximum zoom. When the zoom value moves from one slice to another, the virtual layer will request data from its source. Also, the first slice has a 2 by 2 lat/long division; this means that map is divided in 4 regions, and the layer only requests data for the current visible regions. The second slice is divided into 16 regions, higher zoom values require more divisions to perform well.
To understand the IMapVirtualSource interface, let's look at an implementation from the Factories sample:
C# |
Copy Code
|
---|---|
public class ServerStoreSource : IMapVirtualSource { public void Request(double minZoom, double maxZoom, Point lowerLeft, Point upperRight, Action<ICollection> callback) { if (minZoom < minStoreZoom) return; var client = CreateFactoriesService(); client.GetStoresCompleted += (s, e) => { if(e.Error == null) callback(e.Result); }; client.GetStoresAsync(lowerLeft.Y, lowerLeft.X, upperRight.Y, upperRight.X); } } |
The Request method receives a region of the map space as parameter, and expects a collection of items to be returned using a callback. This particular implementation first checks if the minimal zoom requested is less than an application parameter, if true it does nothing. Otherwise, it calls a Web service to obtain the data.
Server-side we have the implementation of GetStores. It iterates through all the elements in a database, and returns the items that are inside the bounds requested:
C# |
Copy Code
|
---|---|
public List<Store> GetStores(double lowerLeftLat, double lowerLeftLong, double upperRightLat, double upperRightLong) { var stores = new List<Store>(); var dataBase = DataBase.GetInstance(Context); foreach (var store in dataBase.Stores) { if (store.Latitude > lowerLeftLat && store.Longitude > lowerLeftLong && store.Latitude <= upperRightLat && store.Longitude <= upperRightLong) { stores.Add(store); } } return stores; } |
A better implementation should have the stores already divided in regions to prevent iterating through all of them.