提高使用具有许多子项的 MapLayer 时 Bing Maps for Silverlight 的性能

发布于 2024-12-07 16:29:39 字数 1363 浏览 4 评论 0原文

我有一个使用 Bing 地图的 Silverlight 应用程序。我需要在地球表面显示大约 10,000 个标记。这些标记是简单的 Path 实例,其中大多数具有相同的形状,尽管它们具有不同的旋转(通过 RotateTransform 应用)。

目前性能约为 6 FPS。我尝试了各种方法来改善这种情况,但没有什么比这更好的了。

逻辑树类似于:

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

但是,Path 实例是以编程方式添加的。它们的位置是通过绑定建立的,尽管这些绑定在平移过程中不会触发,因此不应导致我所看到的问题。

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

我尝试为 MapLayer 启用 GPU 加速和位图缓存,并通过观察 Process Explorer 中的 GPU 统计数据以及在 Silverlight 主机中启用 FPS 计数器/缓存覆盖来验证这是否已正确启用。这对 FPS 影响很小或没有影响。即使这确实有帮助,也不可能缓存高于某个阈值(2048 像素平方?)的位图,因此当您放大一点时,它会退回到软件渲染。

使用 dotTrace CPU 分析器进一步深入研究,似乎限制因素是对 Measure/Arrange 的重复调用。我怀疑这是因为当地图左侧的子项向左滚动得足够远时,它们会环绕地球并移动到最右侧(反之亦然),这会导致布局以及任何位图无效缓存。我认为没有简单的方法可以支付这笔罚款。

有其他人遇到过这个问题,并且理想地找到了探索的途径吗?

一些随机的想法可以尝试:

  • 直接从 MapLayerBase 而不是 MapLayer 派生,并自己实现布局算法,绕过 MapLayer.PositionProperty 依赖属性并完全支持 IProjectable
  • 使用 MapItemsControl 而不是 MapLayer 进行调查。
  • 将子项投影到图像上并渲染为更简单的图块。

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

沉溺在你眼里的海 2024-12-14 16:29:39

为了加速基本的平移和缩放操作,您可以通过继承 MapLayer 并挂钩到父地图的 ViewChange 事件来禁用(在鼠标事件期间)标记丰富图层的渲染,如下所示。我忘记了我最初是在哪里找到这个的,所以如果所有者想获得荣誉,请继续——当你有大约 10K 个 pin 时,这对于保持至少一致的平移 UI 体验非常有用。除此之外,我会使用一些自定义集群,这显然更多地涉及模型层。华泰

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
}

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
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文