Select to view content in your preferred language

Dynamically adding/removing GraphicOverlays

779
2
02-15-2023 05:24 PM
BrianLoehr
Emerging Contributor

I'm using Esri.ArcGISRuntime.Maui v200.0.0. Admittedly I am new to using Esri so maybe there is a more obvious solution: I am wanting to dynamically add  and remove site pins on the map. First attempt was to reuse the initial set of Graphic objects and just build a new GraphicsOverlay and only add the Graphics desired. Then null out the GraphicsOverlays collection and add a new one. This resulted in the Object Already Owned exception.

Second attempt is to create a new GraphicsOverlay along with a new Graphic object for each item and add it to the GraphicsOverlays collection. Removing a GraphicOverlay is as simple as identifying the particular GraphicOverlay and removing it from the GraphicOverlays collection. In this manner I can add and remove as many as desired. 

The question is - is this a viable way to perform the action I desire? Will there be significant memory or performance issues if adding 100's or 1000's of objects?

// code from view model (using MVVM)

private static SimpleMarkerSymbol _pinSymbol = new SimpleMarkerSymbol(SimpleMarkerSymbolStyle.Diamond, Color.OrangeRed, 12);

private static readonly MapPoint[] _sitePoints = new[]
        {
            new MapPoint(-97.7805, 30.4027, SpatialReferences.Wgs84),
            new MapPoint(-97.8005, 30.4227, SpatialReferences.Wgs84),
            new MapPoint(-97.8205, 30.4427, SpatialReferences.Wgs84),
            new MapPoint(-97.8100, 30.4227, SpatialReferences.Wgs84),
            new MapPoint(-97.7900, 30.4027, SpatialReferences.Wgs84)
        };

private void AddPin()
{
    if (GraphicsOverlays == null)
        return;

    if (GraphicsOverlays.Count == 5)
        return;

    // how many pins right now?
    var pinCount = GraphicsOverlays.Count;
    var newPinIndex = pinCount;

    var pinOverlay = new GraphicsOverlay();
    var newGraphic = new Graphic(_sitePoints[newPinIndex], _pinSymbol);
    pinOverlay.Graphics.Add(newGraphic);
    GraphicsOverlays.Add(pinOverlay);
}

private Task RemoveLatestPinLocation()
{
    if (GraphicsOverlays == null)
        return Task.CompletedTask;

    int count = GraphicsOverlays.Count;
    if (count == 0)
        return Task.CompletedTask;

    // update overlay
    var removePinIndex = count - 1;
    var overlayToRemove = GraphicsOverlays.ElementAt(removePinIndex);
    if (overlayToRemove == null)
        return Task.CompletedTask;

    GraphicsOverlays.Remove(overlayToRemove);

    return Task.CompletedTask;
}

 

0 Kudos
2 Replies
MatveiStefarov
Esri Contributor

Graphic is an interactive object -- adding it to an overlay does not merely make a copy.  You can keep changing a Graphic after it's added to an overlay, and it will reflect changes to geometry and attributes.  A Graphic can only belong to one Overlay at a time.  If you want to move it from one overlay to another, remove it from the first overlay before adding to the second -- this avoids the "object already owned" exception.

GraphicsOverlays are similar.  They belong to one GeoView at a time, and you can keep interacting with an overlay (e.g. adding/removing Graphics) after it's been added to a GeoView.  Remove it first if you want to move to a different GeoView.

In general, reusing Graphics is probably not worth the effort until you get into hundreds of updates per second.  You can create new ones on demand.  However I do recommend using a Renderer on the overlay instead of assigning symbols to individual graphics.

GraphicsOverlays are heavier objects, but you shouldn't need too many of them.  One overlay can hold unlimited number of Graphics, and you can keep adding/updating/removing Graphics as needed.

0 Kudos
BrianLoehr
Emerging Contributor

Thank you @MatveiStefarov for your quick response and detailed reply!

0 Kudos