In my Windows Phone 8 app, I have map control which has collection of planes (pushpins).
Map is defined in xaml like this:
<maps:Map x:Name="Map">
<maptk:MapExtensions.Children>
<maptk:MapItemsControl Name="Planes" ItemTemplate="{StaticResource PlaneTemplate}"/>
</maptk:MapExtensions.Children>
</maps:Map>
Planes MapItemsControl is bind to collection (ObservableCollection) of objects in view model like this:
private ObservableCollection<IPlane> _planes;
public ObservableCollection<IPlane> Planes
{
get { return _planes; }
set
{
_planes = value;
NotifyOfPropertyChange(() => Planes);
}
}
public async void GetPlanes()
{
IReadOnlyCollection<IPlane> planes = await realtimePlanes.GetAllPlanesAsync();
foreach (IPlane newPlane in planes)
{
this.Vehicles.Add(newPlane);
}
}
When I call the GetPlaes(), to get the planes from web api and update the collection, the whole app freeses for couple of seconds. Typically there is something like 150 - 300 items in Planes collectoin.
How should I improve this to make the user experience better, to remove the lag when I update the Planes collection?
Can I somehow force this collection update to be made in background thread(?) or is the problem map control performance? It can not draw all items fast enough in one go?
UPDATE
Here is some more code, how my actual app works.
Just build quick and dirty test class/service to generate test planes:
public class TestRealtimePlaneService : IRealtimePlaneService
{
private Random random;
public async Task<IEnumerable<IRealtimePlane>> GetAllPlanesAsync()
{
this.random = new Random();
int count = 350;
double x0 = 24.9375;
double y0 = 60.170833;
int radius = 8000;
List<TestRealtimePlane> planes = new List<TestRealtimePlane>();
for (int i = 0; i < count; i++)
{
planes.Add(new TestRealtimePlane() { Location = getLocation(x0, y0, radius), Bearing = 1 });
}
await Task.Delay(5000); // Just to simulate webservice call
return planes;
}
// Taken from http://gis.stackexchange.com/questions/25877/how-to-generate-random-locations-nearby-my-location
public GeoCoordinate getLocation(double x0, double y0, int radius)
{
double radiusInDegrees = radius / 111000f;
double u = this.random.NextDouble();
double v = this.random.NextDouble();
double w = radiusInDegrees * Math.Sqrt(u);
double t = 2 * Math.PI * v;
double x = w * Math.Cos(t);
double y = w * Math.Sin(t);
double new_x = x / Math.Cos(y0);
double foundLongitude = new_x + x0;
double foundLatitude = y + y0;
return new GeoCoordinate(foundLatitude, foundLongitude);
}
}
And here is the actual map component
<maps:Map x:Name="Map">
<maptk:MapExtensions.Children>
<maptk:MapItemsControl Name="Planes">
<maptk:MapItemsControl.ItemTemplate>
<DataTemplate>
<maptk:Pushpin GeoCoordinate="{Binding Location}" PositionOrigin="0.5,0.5">
<maptk:Pushpin.Template>
<ControlTemplate TargetType="maptk:Pushpin">
<Grid Width="45" Height="45" Background="Transparent">
<Polygon Fill="Yellow" Points="22,0 34,13, 12,13" Width="45" Height="45" RenderTransformOrigin="0.5,0.5">
<Polygon.RenderTransform>
<RotateTransform CenterX="0.5" CenterY="0.5" Angle="{Binding Bearing}"/>
</Polygon.RenderTransform>
</Polygon>
<Ellipse Fill="Yellow" Stroke="Black" HorizontalAlignment="Center" VerticalAlignment="Center" Width="15" Height="15" StrokeThickness="2" />
</Grid>
</ControlTemplate>
</maptk:Pushpin.Template>
</maptk:Pushpin>
</DataTemplate>
</maptk:MapItemsControl.ItemTemplate>
</maptk:MapItemsControl>
</maptk:MapExtensions.Children>
</maps:Map>
It seems that the pushpin template also affects quite lot for the performance. If I remove my own control template from pushpin, this works gain just little bit faster.