Повышение производительности Bing Maps для Silverlight при использовании MapLayer со многими дочерними элементами - PullRequest
2 голосов
/ 03 октября 2011

У меня есть приложение Silverlight, которое использует Bing Maps.Мне нужно показать ~ 10000 маркеров по всей поверхности Земли.Эти маркеры являются простыми 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, а также включая счетчики FPS / наложения кэша на хосте Silverlight.Это мало или совсем не влияло на FPS.Даже если это помогло, невозможно кэшировать растровые изображения выше некоторого порогового значения (квадрат 2048 пикселей?), И поэтому при небольшом увеличении масштабирования возвращается к программному рендерингу.

Немного углубимся вПрофилировщик CPU dotTrace, похоже, ограничивающим фактором является повторные вызовы Measure / Arrange.Я подозреваю, что это потому, что, поскольку дети слева от карты прокручиваются достаточно далеко влево, они оборачиваются вокруг Земли и перемещаются в крайнее правое положение (и наоборот), что приводит к аннулированию макета, а также любого растрового изображениякэш.Я не думаю, что есть простой способ обойти это наказание.

Кто-нибудь еще сталкивался с этой проблемой и в идеале нашел путь для исследования?

Некоторые случайные идеи вещей, которые можно попробовать:

  • Извлечение непосредственно из MapLayerBase вместо MapLayer и самостоятельная реализация алгоритма компоновки, без учета свойства зависимости MapLayer.PositionProperty и общей поддержки IProjectable.
  • Расследование с использованиемMapItemsControl вместо MapLayer.
  • Проецирование дочерних элементов на изображения и рендеринг в виде простых плиток.

1 Ответ

4 голосов
/ 16 декабря 2011

Чтобы ускорить основные операции панорамирования и масштабирования, вы можете отключить (во время событий мыши) рендеринг слоев с маркерами, унаследовав их от MapLayer и подключив события ViewChange родительской карты следующим образом.Я забыл, где я нашел это изначально, поэтому, если владелец хочет взять кредит, продолжайте - очень полезно для поддержания как минимум постоянного интерфейса панорамирования, когда вы набираете 10K кеглей.Помимо этого, я бы использовал некоторую пользовательскую кластеризацию, которая, очевидно, больше задействована на уровне модели.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
}
...