开发者

Improving performance of Bing Maps for Silverlight when using a MapLayer with many child items

I have a Silverlight app that's using Bing Maps. I need to show ~10,000 markers across Earth's surface. These markers are simple Path instances, most of which are the same shape, although they have different rotations, which are applied via a RotateTransform.

Performance is at around 6 FPS right now. I've tried various approaches to improve the situation, but nothing is getting higher than that.

The logical tree resembles:

<Map>
  <MapLayer>
    <Path ... />
    <Path ... />
    <Path ... /> <!-- and so on, several thousand times -->

The Path instances are added programmatically however. Their positions are established via bindings, though these bindings do not fire during panning and so shouldn't be contributing to the problems I'm seeing.

var path = new Path { /* ... */ };
path.SetBinding(MapLayer.PositionProperty, new Binding("Location")
{
    Source = asset,
    Mode = BindingMode.OneWay
});

I tried enabling GPU acceleration and bitmap caching for the MapLayer and validated that this was correctly enabled by observing GPU stats in Process Explorer, and enabling FPS counters/cache overlays in the Silverlight host as well. This had little or no effect on FPS. Even if this did help, it's not possible to cache bitmaps above some threshold (2048 pixels square?) and so when you zoom in a little, it falls back to software rendering.

Digging in a little further with the dotTrace CPU profiler, it seems that the limiting factor is repeated calls to Measure/Arrange. I suspect this is because as children to the left of the map are scrolled far enough to the left, they wrap around Earth and are moved to the far right (and vice versa), which causes invalidation of the layout, as well as any bitmap cache. I don'开发者_开发知识库t think there is an easy way around paying this penalty.

Has anyone else encountered this issue, and ideally found an avenue for exploration?

Some random ideas of things to try:

  • Deriving directly from MapLayerBase instead of MapLayer and implementing the layout algorithm myself, bypassing the MapLayer.PositionProperty dependency property and support for IProjectable altogether.
  • Investigate using MapItemsControl instead of MapLayer.
  • Projecting children onto images and rendering as simpler tiles.


To speed up basic pan and zoom operations, you can disable (during the mouse events) the render of marker-rich layers by inheriting from MapLayer and hooking into the parent map's ViewChange events as follows. I forget where I found this originally so if the owner wants to take credit go ahead -- very useful for maintaining at least a consistent panning UI experience when you're up around 10K pins. Beyond that I would use some custom clustering, which is more involved at the model layer obviously. HTH

public class OnPanDisableRenderMapLayer : MapLayer
{
    #region Private Properties

    private Visibility _visibility; 

    #endregion 

    #region Constructor 

    ///<summary>
    /// Constructor
    ///</summary>
    public OnPanDisableRenderMapLayer()
        : base()
    {
        this.Loaded += (sender, evt) =>
        {
            Map map = (Map)base.ParentMap;
            map.ViewChangeStart += (s, e) =>
            {
                _visibility = base.Visibility; 

                if (base.Visibility == Visibility.Visible)
                {
                    base.Visibility = Visibility.Collapsed;
                }
            }; 

            map.ViewChangeEnd += (s, e) =>
            {
                base.Visibility = _visibility;
            };
        };
    } 

    #endregion 

    #region Public Properties 

    public Visibility Visibility
    {
        get { return base.Visibility; }
        set
        {
            base.Visibility = value;
            _visibility = value;
        }
    } 

    #endregion
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜