4

End goal: Allow user to move points on a ILineElement using the selection handles from ISelectionTracker.

Issue: Using my code below I am able to get the handles to appear on the line element, but it appears to be using an EnvelopeTracker and not a LineTracker. Also I am unable to drag the displayed handles to reshape the line.

Code:

public void TrackSelection()
{
    IGraphicsContainerSelect graphicsContainer = (IGraphicsContainerSelect)GetGraphicsContainer();          
    ILineElement outline = GetLine();
    // Selecting the element adds the tracker handles.
    graphicsContainer.SelectElement((IElement)outline);

    RefreshView();
}

private ILineElement GetLine()
{             
    //For simplicity only 1 line is created so just grab it.
    ILineElement line = null;
    IGraphicsContainer graphicsContainer = GetGraphicsContainer();
    if (graphicsContainer != null)
    {
        graphicsContainer.Reset();
        IElement element = graphicsContainer.Next();
        while (element != null)
        {
            if (element is ILineElement)
            {
                line = (ILineElement)element;
            }

            element = graphicsContainer.Next();
        }
    }

    return line;
}

public void RandomLineElementCreator()
{
    // Random line creator. Replacing.
    IGraphicsContainer graphicsContainer = GetGraphicsContainer();
    if (graphicsContainer != null)
    {
        graphicsContainer.DeleteAllElements();

        IColor color = EsriConversionUtility.ConvertToRgbColor(Colors.Red);
        ISimpleLineSymbol simpleLineSymbol = new SimpleLineSymbolClass();
        simpleLineSymbol.Color = color;
        simpleLineSymbol.Width = 3;

        IPointCollection path = new PathClass();
        var line = new PolylineClass();
        Random rnd = new Random();                
        for (int i = 0; i < 4; i++)
        {
            int randomX = rnd.Next(1, 8);
            int randomY = rnd.Next(1, 16);
            var point = new Point();
            point.X = -12831100.742200622 - (randomX * 1000);
            point.Y = 7674669.7012844728 - (randomY * 1000);
            path.AddPoint(point);
        }
        line.IPointCollection4_AddPointCollection(path);

        IGeometry geometry = line;


        ILineElement lineElement = new LineElementClass();
        lineElement.Symbol = simpleLineSymbol;
        IElement elementToAdd = lineElement as IElement;
        elementToAdd.Geometry = geometry;
        graphicsContainer.AddElement(elementToAdd, 0);

        RefreshView();                
    }
}

private IGraphicsContainer GetGraphicsContainer()
{
    ICompositeGraphicsLayer compositeGraphicsLayer = (ICompositeGraphicsLayer)(MapController.Map.BasicGraphicsLayer);
    try
    {
        _graphicsLayer = compositeGraphicsLayer.FindLayer(EditContourGraphicsLayerName);
    }
    catch
    {
        _graphicsLayer = compositeGraphicsLayer.AddLayer(EditContourGraphicsLayerName, null);
    }

    return _graphicsLayer as IGraphicsContainer;
}

private void RefreshView()
{
    MapController.PartialRefreshMap();
    if (ActiveMap.Instance.IsInitialized)
    {
        ActiveMap.Instance.Map.IsDirty = true;
    }
}

What I have:

enter image description here

What I want:

enter image description here

  • 1
    Did you try IReshapeFeedback ? desktop.arcgis.com/en/arcobjects/latest/net/… (or maybe IReshapeFeedback2). – Kirk Kuykendall Sep 20 '18 at 17:08
  • Neither ILineElement or IElement have a path property so it doesn't seem I can use this here. – scott lafoy Sep 20 '18 at 20:56
  • Can you assume that the geometry returned by IElement.Geometry is an IGeometryCollection with only one IPath in it? – Kirk Kuykendall Sep 20 '18 at 21:03
  • Yes I think I can, Ill look into if I can use this. – scott lafoy Sep 20 '18 at 21:34
  • I am unable to get IReshapeFeedback to work or find an example of how to use it. – scott lafoy Sep 24 '18 at 13:35
1

Ok, after a long time messing around with this and many many dead ends I have finally figured it out. I really hope this can save someone a bunch of time.

The first issue was getting the drag handles to show on the point on the line and not the envelope. The magic came from IElementEditVertices

public void TrackSelection()
{
    var activeView = (IActiveView)MapController.Map;
    IScreenDisplay screenDisplay = ((IActiveView)MapController.Map).ScreenDisplay;

    IGraphicsContainerSelect graphicsContainer = (IGraphicsContainerSelect)GetGraphicsContainer();
    ILineElement lineElement = GetLine();
    // Selecting the element adds the tracker handles.
    graphicsContainer.SelectElement((IElement)lineElement);

    if (lineElement is IElementEditVertices)
    {
        // This is needed to get tracker handles to show on points and not the envelope.
        IElementEditVertices elementEditVertices = lineElement as IElementEditVertices;
        if ((elementEditVertices.MovingVertices == false))
        {
            elementEditVertices.MovingVertices = true;
            IElement element = lineElement as IElement;
            activeView.PartialRefresh(esriViewDrawPhase.esriViewGraphicSelection, null,
                element.SelectionTracker.get_Bounds(screenDisplay));
        }
    }

    EnsureEnvelopeTracker(activeView, (IElement)lineElement);
}

Then came the task of how to grab the handles and move them afterwards. Using the IReshapeFeedback like Kirk suggested was working but the easier way is to use the mouse move method on the ISelectionTracker so you don't have to worry about grabbing a point under the mouse then moving it and finally updating its position. Eventhough you have to add your own mouse handlers this is very simple. Just do not forget to set the ISelectionTracker.Display otherwise mouse down will crash with a cryptic error.

private ISelectionTracker selectionTracker;
private IElement element;

public void SelectionTrackerMouseDown(int button, int shift, int x, int y)
{
    var activeView = (IActiveView)MapController.Map;
    ILineElement line = GetLine();
    IElement element = (IElement)line;
    // This is the magic interface that puts the handles on the points.
    IElementEditVertices editElement = element as IElementEditVertices;
    editElement.MovingVertices = true;
    selectionTracker = element.SelectionTracker;
    selectionTracker.ShowHandles = true;
    selectionTracker.Locked = false;
    // Without setting the display here this will crash.
    selectionTracker.Display = activeView.ScreenDisplay;

    // This is what actually moves the point around, the rest is just setting up the selection tracker.
    selectionTracker.OnMouseDown(button, shift, x, y);
}

public void SelectionTrackerMousemove(int button, int shift, int x, int y)
{
    //Pass on the mouse move event to the selection tracker.
    if (selectionTracker != null)
    {
        selectionTracker.OnMouseMove(button, shift, x, y);
    }
}

public void SelectionTrackerMousUp(int button, int shift, int x, int y)
{
    if (selectionTracker != null)
    {
        selectionTracker.OnMouseUp(button, shift, x, y);
        IGraphicsContainer esriViewGraphicSelection = (IGraphicsContainer)GetGraphicsContainer();
        var geometry = selectionTracker.Geometry;

        IGraphicsContainer graphicsContainer = GetGraphicsContainer();
        IColor color = EsriConversionUtility.ConvertToRgbColor(Colors.Red);
        ISimpleLineSymbol simpleLineSymbol = new SimpleLineSymbolClass();
        simpleLineSymbol.Color = color;
        simpleLineSymbol.Width = 3;

        ILineElement lineElement = new LineElementClass();
        lineElement.Symbol = simpleLineSymbol;
        IElement elementToAdd = lineElement as IElement;
        elementToAdd.Geometry = geometry;
        graphicsContainer.DeleteAllElements();
        // TODO {Sep 27, 2018} Look into an update instead of a delete and re-add.
        graphicsContainer.AddElement(elementToAdd,0);

        var activeView = (IActiveView)MapController.Map;
        RefreshView();
        selectionTracker = null;
    }
}

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.